blob: 5ce01f1379a4a23f09924848bf949fad341012eb [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-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 Peller9eb599e2011-10-10 10:12:59 +0200505static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
506 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300507{
508 int ret = 0;
509
510 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200511 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300512 if (ret < 0)
513 goto out;
514
515 if (enable)
516 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
517 else
518 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
519out:
520 return ret;
521}
522
523/*
524 * this function is being called when the rx_streaming interval
525 * has beed changed or rx_streaming should be disabled
526 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200527int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300528{
529 int ret = 0;
530 int period = wl->conf.rx_streaming.interval;
531
532 /* don't reconfigure if rx_streaming is disabled */
533 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
534 goto out;
535
536 /* reconfigure/disable according to new streaming_period */
537 if (period &&
538 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
539 (wl->conf.rx_streaming.always ||
540 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200545 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300546 }
547out:
548 return ret;
549}
550
551static void wl1271_rx_streaming_enable_work(struct work_struct *work)
552{
553 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200554 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
555 rx_streaming_enable_work);
556 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300557
558 mutex_lock(&wl->mutex);
559
560 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
561 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
562 (!wl->conf.rx_streaming.always &&
563 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
564 goto out;
565
566 if (!wl->conf.rx_streaming.interval)
567 goto out;
568
569 ret = wl1271_ps_elp_wakeup(wl);
570 if (ret < 0)
571 goto out;
572
Eliad Peller9eb599e2011-10-10 10:12:59 +0200573 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300574 if (ret < 0)
575 goto out_sleep;
576
577 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300579 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
580
581out_sleep:
582 wl1271_ps_elp_sleep(wl);
583out:
584 mutex_unlock(&wl->mutex);
585}
586
587static void wl1271_rx_streaming_disable_work(struct work_struct *work)
588{
589 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200590 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
591 rx_streaming_disable_work);
592 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300593
594 mutex_lock(&wl->mutex);
595
596 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
597 goto out;
598
599 ret = wl1271_ps_elp_wakeup(wl);
600 if (ret < 0)
601 goto out;
602
Eliad Peller9eb599e2011-10-10 10:12:59 +0200603 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300604 if (ret)
605 goto out_sleep;
606
607out_sleep:
608 wl1271_ps_elp_sleep(wl);
609out:
610 mutex_unlock(&wl->mutex);
611}
612
613static void wl1271_rx_streaming_timer(unsigned long data)
614{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200615 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
616 struct wl1271 *wl = wlvif->wl;
617 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300618}
619
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620static void wl1271_conf_init(struct wl1271 *wl)
621{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300622
623 /*
624 * This function applies the default configuration to the driver. This
625 * function is invoked upon driver load (spi probe.)
626 *
627 * The configuration is stored in a run-time structure in order to
628 * facilitate for run-time adjustment of any of the parameters. Making
629 * changes to the configuration structure will apply the new values on
630 * the next interface up (wl1271_op_start.)
631 */
632
633 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300634 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300635
Ido Yariv95dac04f2011-06-06 14:57:06 +0300636 /* Adjust settings according to optional module parameters */
637 if (fwlog_param) {
638 if (!strcmp(fwlog_param, "continuous")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
640 } else if (!strcmp(fwlog_param, "ondemand")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
642 } else if (!strcmp(fwlog_param, "dbgpins")) {
643 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
644 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
645 } else if (!strcmp(fwlog_param, "disable")) {
646 wl->conf.fwlog.mem_blocks = 0;
647 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
648 } else {
649 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
650 }
651 }
652}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654static int wl1271_plt_init(struct wl1271 *wl)
655{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200656 struct conf_tx_ac_category *conf_ac;
657 struct conf_tx_tid *conf_tid;
658 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659
Shahar Levi49d750ca2011-03-06 16:32:09 +0200660 if (wl->chip.id == CHIP_ID_1283_PG20)
661 ret = wl128x_cmd_general_parms(wl);
662 else
663 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200664 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200665 return ret;
666
Shahar Levi49d750ca2011-03-06 16:32:09 +0200667 if (wl->chip.id == CHIP_ID_1283_PG20)
668 ret = wl128x_cmd_radio_parms(wl);
669 else
670 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200671 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200672 return ret;
673
Shahar Levi49d750ca2011-03-06 16:32:09 +0200674 if (wl->chip.id != CHIP_ID_1283_PG20) {
675 ret = wl1271_cmd_ext_radio_parms(wl);
676 if (ret < 0)
677 return ret;
678 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200679 if (ret < 0)
680 return ret;
681
Shahar Levi48a61472011-03-06 16:32:08 +0200682 /* Chip-specific initializations */
683 ret = wl1271_chip_specific_init(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller92c77c72011-10-05 11:55:40 +0200687 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200688 if (ret < 0)
689 return ret;
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = wl1271_acx_init_mem_config(wl);
692 if (ret < 0)
693 return ret;
694
Luciano Coelho12419cc2010-02-18 13:25:44 +0200695 /* PHY layer config */
696 ret = wl1271_init_phy_config(wl);
697 if (ret < 0)
698 goto out_free_memmap;
699
700 ret = wl1271_acx_dco_itrim_params(wl);
701 if (ret < 0)
702 goto out_free_memmap;
703
704 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200705 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200706 if (ret < 0)
707 goto out_free_memmap;
708
709 /* Bluetooth WLAN coexistence */
710 ret = wl1271_init_pta(wl);
711 if (ret < 0)
712 goto out_free_memmap;
713
Shahar Leviff868432011-04-11 15:41:46 +0300714 /* FM WLAN coexistence */
715 ret = wl1271_acx_fm_coex(wl);
716 if (ret < 0)
717 goto out_free_memmap;
718
Luciano Coelho12419cc2010-02-18 13:25:44 +0200719 /* Energy detection */
720 ret = wl1271_init_energy_detection(wl);
721 if (ret < 0)
722 goto out_free_memmap;
723
Eliad Peller7f0979882011-08-14 13:17:06 +0300724 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600725 if (ret < 0)
726 goto out_free_memmap;
727
Luciano Coelho12419cc2010-02-18 13:25:44 +0200728 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100729 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200730 if (ret < 0)
731 goto out_free_memmap;
732
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200733 /* Default TID/AC configuration */
734 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200736 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200737 /* TODO: fix */
738 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200739 conf_ac->cw_max, conf_ac->aifsn,
740 conf_ac->tx_op_limit);
741 if (ret < 0)
742 goto out_free_memmap;
743
Luciano Coelho12419cc2010-02-18 13:25:44 +0200744 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200745 /* TODO: fix */
746 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 conf_tid->channel_type,
748 conf_tid->tsid,
749 conf_tid->ps_scheme,
750 conf_tid->ack_policy,
751 conf_tid->apsd_conf[0],
752 conf_tid->apsd_conf[1]);
753 if (ret < 0)
754 goto out_free_memmap;
755 }
756
Luciano Coelho12419cc2010-02-18 13:25:44 +0200757 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200758 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200760 goto out_free_memmap;
761
762 /* Configure for CAM power saving (ie. always active) */
763 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
764 if (ret < 0)
765 goto out_free_memmap;
766
767 /* configure PM */
768 ret = wl1271_acx_pm_config(wl);
769 if (ret < 0)
770 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
772 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200773
774 out_free_memmap:
775 kfree(wl->target_mem_map);
776 wl->target_mem_map = NULL;
777
778 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779}
780
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300781static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200782{
Arik Nemtsovda032092011-08-25 12:43:15 +0300783 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300786 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787
788 /*
789 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300790 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200791 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300792 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200793 wl1271_ps_link_end(wl, hlid);
794
Arik Nemtsovda032092011-08-25 12:43:15 +0300795 /*
796 * Start high-level PS if the STA is asleep with enough blocks in FW.
797 * Make an exception if this is the only connected station. In this
798 * case FW-memory congestion is not a problem.
799 */
800 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200801 wl1271_ps_link_start(wl, hlid, true);
802}
803
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300804static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200805 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300806 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200807{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200808 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200809 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300810 u8 hlid, cnt;
811
812 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200813
814 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
815 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
816 wl1271_debug(DEBUG_PSM,
817 "link ps prev 0x%x cur 0x%x changed 0x%x",
818 wl->ap_fw_ps_map, cur_fw_ps_map,
819 wl->ap_fw_ps_map ^ cur_fw_ps_map);
820
821 wl->ap_fw_ps_map = cur_fw_ps_map;
822 }
823
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200824 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
825 lnk = &wl->links[hlid];
826 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200827
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200828 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
829 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200830
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_ps_regulate_link(wl, hlid, lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200832 }
833}
834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835static void wl12xx_fw_status(struct wl1271 *wl,
836 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837{
Eliad Peller536129c82011-10-05 11:55:45 +0200838 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
839 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200840 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200841 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300842 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300843 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844
Eliad Peller4d56ad92011-08-14 13:17:05 +0300845 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
848 "drv_rx_counter = %d, tx_results_counter = %d)",
849 status->intr,
850 status->fw_rx_counter,
851 status->drv_rx_counter,
852 status->tx_results_counter);
853
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300854 for (i = 0; i < NUM_TX_QUEUES; i++) {
855 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300856 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300857 (status->tx_released_pkts[i] -
858 wl->tx_pkts_freed[i]) & 0xff;
859
860 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
861 }
862
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300863 /* prevent wrap-around in total blocks counter */
864 if (likely(wl->tx_blocks_freed <=
865 le32_to_cpu(status->total_released_blks)))
866 freed_blocks = le32_to_cpu(status->total_released_blks) -
867 wl->tx_blocks_freed;
868 else
869 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
870 le32_to_cpu(status->total_released_blks);
871
Eliad Peller4d56ad92011-08-14 13:17:05 +0300872 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200873
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300874 wl->tx_allocated_blocks -= freed_blocks;
875
Eliad Peller4d56ad92011-08-14 13:17:05 +0300876 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200877
Eliad Peller4d56ad92011-08-14 13:17:05 +0300878 /*
879 * The FW might change the total number of TX memblocks before
880 * we get a notification about blocks being released. Thus, the
881 * available blocks calculation might yield a temporary result
882 * which is lower than the actual available blocks. Keeping in
883 * mind that only blocks that were allocated can be moved from
884 * TX to RX, tx_blocks_available should never decrease here.
885 */
886 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
887 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888
Ido Yariva5225502010-10-12 14:49:10 +0200889 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200890 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200891 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892
Eliad Peller4d56ad92011-08-14 13:17:05 +0300893 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller536129c82011-10-05 11:55:45 +0200894 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200895 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200898 getnstimeofday(&ts);
899 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
900 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901}
902
Ido Yariva6208652011-03-01 15:14:41 +0200903static void wl1271_flush_deferred_work(struct wl1271 *wl)
904{
905 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200906
Ido Yariva6208652011-03-01 15:14:41 +0200907 /* Pass all received frames to the network stack */
908 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
909 ieee80211_rx_ni(wl->hw, skb);
910
911 /* Return sent skbs to the network stack */
912 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300913 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200914}
915
916static void wl1271_netstack_work(struct work_struct *work)
917{
918 struct wl1271 *wl =
919 container_of(work, struct wl1271, netstack_work);
920
921 do {
922 wl1271_flush_deferred_work(wl);
923 } while (skb_queue_len(&wl->deferred_rx_queue));
924}
925
926#define WL1271_IRQ_MAX_LOOPS 256
927
928irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300931 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200932 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200933 struct wl1271 *wl = (struct wl1271 *)cookie;
934 bool done = false;
935 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200936 unsigned long flags;
937
938 /* TX might be handled here, avoid redundant work */
939 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
940 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941
Ido Yariv341b7cd2011-03-31 10:07:01 +0200942 /*
943 * In case edge triggered interrupt must be used, we cannot iterate
944 * more than once without introducing race conditions with the hardirq.
945 */
946 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
947 loopcount = 1;
948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 mutex_lock(&wl->mutex);
950
951 wl1271_debug(DEBUG_IRQ, "IRQ work");
952
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200953 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954 goto out;
955
Ido Yariva6208652011-03-01 15:14:41 +0200956 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957 if (ret < 0)
958 goto out;
959
Ido Yariva6208652011-03-01 15:14:41 +0200960 while (!done && loopcount--) {
961 /*
962 * In order to avoid a race with the hardirq, clear the flag
963 * before acknowledging the chip. Since the mutex is held,
964 * wl1271_ps_elp_wakeup cannot be called concurrently.
965 */
966 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
967 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200968
Eliad Peller4d56ad92011-08-14 13:17:05 +0300969 wl12xx_fw_status(wl, wl->fw_status);
970 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200971 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200972 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200973 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200974 continue;
975 }
976
Eliad Pellerccc83b02010-10-27 14:09:57 +0200977 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
978 wl1271_error("watchdog interrupt received! "
979 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300980 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200981
982 /* restarting the chip. ignore any other interrupt. */
983 goto out;
984 }
985
Ido Yariva6208652011-03-01 15:14:41 +0200986 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200987 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
988
Eliad Peller4d56ad92011-08-14 13:17:05 +0300989 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200990
Ido Yariva5225502010-10-12 14:49:10 +0200991 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200992 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200993 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300994 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200995 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200996 /*
997 * In order to avoid starvation of the TX path,
998 * call the work function directly.
999 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001000 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001001 } else {
1002 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001003 }
1004
Ido Yariv8aad2462011-03-01 15:14:38 +02001005 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001006 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001007 (wl->tx_results_count & 0xff))
1008 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001009
1010 /* Make sure the deferred queues don't get too long */
1011 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1012 skb_queue_len(&wl->deferred_rx_queue);
1013 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1014 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001015 }
1016
1017 if (intr & WL1271_ACX_INTR_EVENT_A) {
1018 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1019 wl1271_event_handle(wl, 0);
1020 }
1021
1022 if (intr & WL1271_ACX_INTR_EVENT_B) {
1023 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1024 wl1271_event_handle(wl, 1);
1025 }
1026
1027 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1028 wl1271_debug(DEBUG_IRQ,
1029 "WL1271_ACX_INTR_INIT_COMPLETE");
1030
1031 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1032 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 }
1034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 wl1271_ps_elp_sleep(wl);
1036
1037out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001038 spin_lock_irqsave(&wl->wl_lock, flags);
1039 /* In case TX was not handled here, queue TX work */
1040 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1041 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001042 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001043 ieee80211_queue_work(wl->hw, &wl->tx_work);
1044 spin_unlock_irqrestore(&wl->wl_lock, flags);
1045
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001047
1048 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049}
Ido Yariva6208652011-03-01 15:14:41 +02001050EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052static int wl1271_fetch_firmware(struct wl1271 *wl)
1053{
1054 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001055 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056 int ret;
1057
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001058 if (wl->chip.id == CHIP_ID_1283_PG20)
1059 fw_name = WL128X_FW_NAME;
1060 else
1061 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062
1063 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1064
1065 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
1067 if (ret < 0) {
1068 wl1271_error("could not get firmware: %d", ret);
1069 return ret;
1070 }
1071
1072 if (fw->size % 4) {
1073 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1074 fw->size);
1075 ret = -EILSEQ;
1076 goto out;
1077 }
1078
Arik Nemtsov166d5042010-10-16 21:44:57 +02001079 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001081 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082
1083 if (!wl->fw) {
1084 wl1271_error("could not allocate memory for the firmware");
1085 ret = -ENOMEM;
1086 goto out;
1087 }
1088
1089 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 ret = 0;
1091
1092out:
1093 release_firmware(fw);
1094
1095 return ret;
1096}
1097
1098static int wl1271_fetch_nvs(struct wl1271 *wl)
1099{
1100 const struct firmware *fw;
1101 int ret;
1102
Shahar Levi5aa42342011-03-06 16:32:07 +02001103 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104
1105 if (ret < 0) {
1106 wl1271_error("could not get nvs file: %d", ret);
1107 return ret;
1108 }
1109
Shahar Levibc765bf2011-03-06 16:32:10 +02001110 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 if (!wl->nvs) {
1113 wl1271_error("could not allocate memory for the nvs file");
1114 ret = -ENOMEM;
1115 goto out;
1116 }
1117
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001118 wl->nvs_len = fw->size;
1119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120out:
1121 release_firmware(fw);
1122
1123 return ret;
1124}
1125
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001126void wl12xx_queue_recovery_work(struct wl1271 *wl)
1127{
1128 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1129 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1130}
1131
Ido Yariv95dac04f2011-06-06 14:57:06 +03001132size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1133{
1134 size_t len = 0;
1135
1136 /* The FW log is a length-value list, find where the log end */
1137 while (len < maxlen) {
1138 if (memblock[len] == 0)
1139 break;
1140 if (len + memblock[len] + 1 > maxlen)
1141 break;
1142 len += memblock[len] + 1;
1143 }
1144
1145 /* Make sure we have enough room */
1146 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1147
1148 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1149 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1150 wl->fwlog_size += len;
1151
1152 return len;
1153}
1154
1155static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1156{
1157 u32 addr;
1158 u32 first_addr;
1159 u8 *block;
1160
1161 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1162 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1163 (wl->conf.fwlog.mem_blocks == 0))
1164 return;
1165
1166 wl1271_info("Reading FW panic log");
1167
1168 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1169 if (!block)
1170 return;
1171
1172 /*
1173 * Make sure the chip is awake and the logger isn't active.
1174 * This might fail if the firmware hanged.
1175 */
1176 if (!wl1271_ps_elp_wakeup(wl))
1177 wl12xx_cmd_stop_fwlog(wl);
1178
1179 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001180 wl12xx_fw_status(wl, wl->fw_status);
1181 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001182 if (!first_addr)
1183 goto out;
1184
1185 /* Traverse the memory blocks linked list */
1186 addr = first_addr;
1187 do {
1188 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1189 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1190 false);
1191
1192 /*
1193 * Memory blocks are linked to one another. The first 4 bytes
1194 * of each memory block hold the hardware address of the next
1195 * one. The last memory block points to the first one.
1196 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001197 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001198 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1199 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1200 break;
1201 } while (addr && (addr != first_addr));
1202
1203 wake_up_interruptible(&wl->fwlog_waitq);
1204
1205out:
1206 kfree(block);
1207}
1208
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209static void wl1271_recovery_work(struct work_struct *work)
1210{
1211 struct wl1271 *wl =
1212 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001213 struct wl12xx_vif *wlvif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001214
1215 mutex_lock(&wl->mutex);
1216
1217 if (wl->state != WL1271_STATE_ON)
1218 goto out;
1219
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001220 /* Avoid a recursive recovery */
1221 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1222
Ido Yariv95dac04f2011-06-06 14:57:06 +03001223 wl12xx_read_fwlog_panic(wl);
1224
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001225 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1226 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001227
Eliad Peller2a5bff02011-08-25 18:10:59 +03001228 BUG_ON(bug_on_recovery);
1229
Oz Krakowskib992c682011-06-26 10:36:02 +03001230 /*
1231 * Advance security sequence number to overcome potential progress
1232 * in the firmware during recovery. This doens't hurt if the network is
1233 * not encrypted.
1234 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001235 wl12xx_for_each_wlvif(wl, wlvif) {
1236 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1237 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1238 wlvif->tx_security_seq +=
1239 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1240 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001241
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001242 /* Prevent spurious TX during FW restart */
1243 ieee80211_stop_queues(wl->hw);
1244
Luciano Coelho33c2c062011-05-10 14:46:02 +03001245 if (wl->sched_scanning) {
1246 ieee80211_sched_scan_stopped(wl->hw);
1247 wl->sched_scanning = false;
1248 }
1249
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001250 /* reboot the chipset */
Eliad Peller536129c82011-10-05 11:55:45 +02001251 __wl1271_op_remove_interface(wl, wl->vif, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001252
1253 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1254
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001255 ieee80211_restart_hw(wl->hw);
1256
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001257 /*
1258 * Its safe to enable TX now - the queues are stopped after a request
1259 * to restart the HW.
1260 */
1261 ieee80211_wake_queues(wl->hw);
1262
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001263out:
1264 mutex_unlock(&wl->mutex);
1265}
1266
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267static void wl1271_fw_wakeup(struct wl1271 *wl)
1268{
1269 u32 elp_reg;
1270
1271 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001272 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273}
1274
1275static int wl1271_setup(struct wl1271 *wl)
1276{
1277 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1278 if (!wl->fw_status)
1279 return -ENOMEM;
1280
1281 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1282 if (!wl->tx_res_if) {
1283 kfree(wl->fw_status);
1284 return -ENOMEM;
1285 }
1286
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287 return 0;
1288}
1289
1290static int wl1271_chip_wakeup(struct wl1271 *wl)
1291{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001292 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 int ret = 0;
1294
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001295 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001296 ret = wl1271_power_on(wl);
1297 if (ret < 0)
1298 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001300 wl1271_io_reset(wl);
1301 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302
1303 /* We don't need a real memory partition here, because we only want
1304 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001305 memset(&partition, 0, sizeof(partition));
1306 partition.reg.start = REGISTERS_BASE;
1307 partition.reg.size = REGISTERS_DOWN_SIZE;
1308 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309
1310 /* ELP module wake up */
1311 wl1271_fw_wakeup(wl);
1312
1313 /* whal_FwCtrl_BootSm() */
1314
1315 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001316 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317
1318 /* 1. check if chip id is valid */
1319
1320 switch (wl->chip.id) {
1321 case CHIP_ID_1271_PG10:
1322 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
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;
1329 case CHIP_ID_1271_PG20:
1330 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1331 wl->chip.id);
1332
1333 ret = wl1271_setup(wl);
1334 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001335 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001337 case CHIP_ID_1283_PG20:
1338 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1339 wl->chip.id);
1340
1341 ret = wl1271_setup(wl);
1342 if (ret < 0)
1343 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001344
Ido Yariv0da13da2011-03-31 10:06:58 +02001345 if (wl1271_set_block_size(wl))
1346 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001347 break;
1348 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 }
1354
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001355 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 ret = wl1271_fetch_firmware(wl);
1357 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 }
1360
1361 /* No NVS from netlink, try to get it from the filesystem */
1362 if (wl->nvs == NULL) {
1363 ret = wl1271_fetch_nvs(wl);
1364 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001365 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366 }
1367
1368out:
1369 return ret;
1370}
1371
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372int wl1271_plt_start(struct wl1271 *wl)
1373{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001374 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001375 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376 int ret;
1377
1378 mutex_lock(&wl->mutex);
1379
1380 wl1271_notice("power up");
1381
1382 if (wl->state != WL1271_STATE_OFF) {
1383 wl1271_error("cannot go into PLT state because not "
1384 "in off state: %d", wl->state);
1385 ret = -EBUSY;
1386 goto out;
1387 }
1388
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001389 while (retries) {
1390 retries--;
1391 ret = wl1271_chip_wakeup(wl);
1392 if (ret < 0)
1393 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001395 ret = wl1271_boot(wl);
1396 if (ret < 0)
1397 goto power_off;
1398
1399 ret = wl1271_plt_init(wl);
1400 if (ret < 0)
1401 goto irq_disable;
1402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 wl->state = WL1271_STATE_PLT;
1404 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001405 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001406
Gery Kahn6f07b722011-07-18 14:21:49 +03001407 /* update hw/fw version info in wiphy struct */
1408 wiphy->hw_version = wl->chip.id;
1409 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1410 sizeof(wiphy->fw_version));
1411
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 goto out;
1413
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001414irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001415 mutex_unlock(&wl->mutex);
1416 /* Unlocking the mutex in the middle of handling is
1417 inherently unsafe. In this case we deem it safe to do,
1418 because we need to let any possibly pending IRQ out of
1419 the system (and while we are WL1271_STATE_OFF the IRQ
1420 work function will not do anything.) Also, any other
1421 possible concurrent operations will fail due to the
1422 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001423 wl1271_disable_interrupts(wl);
1424 wl1271_flush_deferred_work(wl);
1425 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001426 mutex_lock(&wl->mutex);
1427power_off:
1428 wl1271_power_off(wl);
1429 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001431 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1432 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433out:
1434 mutex_unlock(&wl->mutex);
1435
1436 return ret;
1437}
1438
Luciano Coelho4623ec72011-03-21 19:26:41 +02001439static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440{
1441 int ret = 0;
1442
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 wl1271_notice("power down");
1444
1445 if (wl->state != WL1271_STATE_PLT) {
1446 wl1271_error("cannot power down because not in PLT "
1447 "state: %d", wl->state);
1448 ret = -EBUSY;
1449 goto out;
1450 }
1451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452 wl1271_power_off(wl);
1453
1454 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001455 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001458 wl1271_disable_interrupts(wl);
1459 wl1271_flush_deferred_work(wl);
1460 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001461 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001462 mutex_lock(&wl->mutex);
1463out:
1464 return ret;
1465}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001466
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001467int wl1271_plt_stop(struct wl1271 *wl)
1468{
1469 int ret;
1470
1471 mutex_lock(&wl->mutex);
1472 ret = __wl1271_plt_stop(wl);
1473 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 return ret;
1475}
1476
Johannes Berg7bb45682011-02-24 14:42:06 +01001477static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478{
1479 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001480 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1481 struct ieee80211_vif *vif = info->control.vif;
1482 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001483 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001484 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001485 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001487 mapping = skb_get_queue_mapping(skb);
1488 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001489
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001490 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001491
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001492 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001493
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001494 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001495 if (hlid == WL12XX_INVALID_LINK_ID ||
1496 !test_bit(hlid, wlvif->links_map)) {
1497 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1498 dev_kfree_skb(skb);
1499 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001500 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001502 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1503 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1504
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001505 wl->tx_queue_count[q]++;
1506
1507 /*
1508 * The workqueue is slow to process the tx_queue and we need stop
1509 * the queue here, otherwise the queue will get too long.
1510 */
1511 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1512 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1513 ieee80211_stop_queue(wl->hw, mapping);
1514 set_bit(q, &wl->stopped_queues_map);
1515 }
1516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517 /*
1518 * The chip specific setup must run before the first TX packet -
1519 * before that, the tx_work will not be initialized!
1520 */
1521
Ido Yarivb07d4032011-03-01 15:14:43 +02001522 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1523 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001524 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001525
Arik Nemtsov04216da2011-08-14 13:17:38 +03001526out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001527 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528}
1529
Shahar Leviae47c452011-03-06 16:32:14 +02001530int wl1271_tx_dummy_packet(struct wl1271 *wl)
1531{
Ido Yariv990f5de2011-03-31 10:06:59 +02001532 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001533 int q;
1534
1535 /* no need to queue a new dummy packet if one is already pending */
1536 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1537 return 0;
1538
1539 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001540
Ido Yariv990f5de2011-03-31 10:06:59 +02001541 spin_lock_irqsave(&wl->wl_lock, flags);
1542 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001543 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001544 spin_unlock_irqrestore(&wl->wl_lock, flags);
1545
1546 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1547 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001548 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001549
1550 /*
1551 * If the FW TX is busy, TX work will be scheduled by the threaded
1552 * interrupt handler function
1553 */
1554 return 0;
1555}
1556
1557/*
1558 * The size of the dummy packet should be at least 1400 bytes. However, in
1559 * order to minimize the number of bus transactions, aligning it to 512 bytes
1560 * boundaries could be beneficial, performance wise
1561 */
1562#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1563
Luciano Coelhocf27d862011-04-01 21:08:23 +03001564static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001565{
1566 struct sk_buff *skb;
1567 struct ieee80211_hdr_3addr *hdr;
1568 unsigned int dummy_packet_size;
1569
1570 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1571 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1572
1573 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001574 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001575 wl1271_warning("Failed to allocate a dummy packet skb");
1576 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001577 }
1578
1579 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1580
1581 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1582 memset(hdr, 0, sizeof(*hdr));
1583 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001584 IEEE80211_STYPE_NULLFUNC |
1585 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001586
Ido Yariv990f5de2011-03-31 10:06:59 +02001587 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001588
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001589 /* Dummy packets require the TID to be management */
1590 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001591
1592 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001593 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001595
Ido Yariv990f5de2011-03-31 10:06:59 +02001596 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001597}
1598
Ido Yariv990f5de2011-03-31 10:06:59 +02001599
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001600static struct notifier_block wl1271_dev_notifier = {
1601 .notifier_call = wl1271_dev_notify,
1602};
1603
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001604#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001605static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1606 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001607{
Eliad Pellere85d1622011-06-27 13:06:43 +03001608 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001609
Eliad Peller94390642011-05-13 11:57:13 +03001610 mutex_lock(&wl->mutex);
1611
Eliad Pellere85d1622011-06-27 13:06:43 +03001612 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1613 goto out_unlock;
1614
Eliad Peller94390642011-05-13 11:57:13 +03001615 ret = wl1271_ps_elp_wakeup(wl);
1616 if (ret < 0)
1617 goto out_unlock;
1618
1619 /* enter psm if needed*/
1620 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1621 DECLARE_COMPLETION_ONSTACK(compl);
1622
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001623 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001624 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001625 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001626 if (ret < 0)
1627 goto out_sleep;
1628
1629 /* we must unlock here so we will be able to get events */
1630 wl1271_ps_elp_sleep(wl);
1631 mutex_unlock(&wl->mutex);
1632
1633 ret = wait_for_completion_timeout(
1634 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1635 if (ret <= 0) {
1636 wl1271_warning("couldn't enter ps mode!");
1637 ret = -EBUSY;
1638 goto out;
1639 }
1640
1641 /* take mutex again, and wakeup */
1642 mutex_lock(&wl->mutex);
1643
1644 ret = wl1271_ps_elp_wakeup(wl);
1645 if (ret < 0)
1646 goto out_unlock;
1647 }
1648out_sleep:
1649 wl1271_ps_elp_sleep(wl);
1650out_unlock:
1651 mutex_unlock(&wl->mutex);
1652out:
1653 return ret;
1654
1655}
1656
Eliad Peller0603d892011-10-05 11:55:51 +02001657static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1658 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001659{
Eliad Pellere85d1622011-06-27 13:06:43 +03001660 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001661
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001662 mutex_lock(&wl->mutex);
1663
Eliad Pellere85d1622011-06-27 13:06:43 +03001664 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1665 goto out_unlock;
1666
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001667 ret = wl1271_ps_elp_wakeup(wl);
1668 if (ret < 0)
1669 goto out_unlock;
1670
Eliad Peller0603d892011-10-05 11:55:51 +02001671 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001672
1673 wl1271_ps_elp_sleep(wl);
1674out_unlock:
1675 mutex_unlock(&wl->mutex);
1676 return ret;
1677
1678}
1679
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001680static int wl1271_configure_suspend(struct wl1271 *wl,
1681 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001682{
Eliad Peller536129c82011-10-05 11:55:45 +02001683 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001684 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c82011-10-05 11:55:45 +02001685 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001686 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001687 return 0;
1688}
1689
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001690static void wl1271_configure_resume(struct wl1271 *wl,
1691 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001692{
1693 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02001694 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1695 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001696
1697 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001698 return;
1699
1700 mutex_lock(&wl->mutex);
1701 ret = wl1271_ps_elp_wakeup(wl);
1702 if (ret < 0)
1703 goto out;
1704
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001705 if (is_sta) {
1706 /* exit psm if it wasn't configured */
1707 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001708 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001709 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001710 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001711 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001712 }
Eliad Peller94390642011-05-13 11:57:13 +03001713
1714 wl1271_ps_elp_sleep(wl);
1715out:
1716 mutex_unlock(&wl->mutex);
1717}
1718
Eliad Peller402e48612011-05-13 11:57:09 +03001719static int wl1271_op_suspend(struct ieee80211_hw *hw,
1720 struct cfg80211_wowlan *wow)
1721{
1722 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001723 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1724 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 int ret;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001729
Eliad Peller4a859df2011-06-06 12:21:52 +03001730 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001731 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 if (ret < 0) {
1733 wl1271_warning("couldn't prepare device to suspend");
1734 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001735 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001736 /* flush any remaining work */
1737 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001738
1739 /*
1740 * disable and re-enable interrupts in order to flush
1741 * the threaded_irq
1742 */
1743 wl1271_disable_interrupts(wl);
1744
1745 /*
1746 * set suspended flag to avoid triggering a new threaded_irq
1747 * work. no need for spinlock as interrupts are disabled.
1748 */
1749 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1750
1751 wl1271_enable_interrupts(wl);
1752 flush_work(&wl->tx_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001753 flush_delayed_work(&wlvif->pspoll_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001754 flush_delayed_work(&wl->elp_work);
1755
Eliad Peller402e48612011-05-13 11:57:09 +03001756 return 0;
1757}
1758
1759static int wl1271_op_resume(struct ieee80211_hw *hw)
1760{
1761 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001762 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1763 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001764 unsigned long flags;
1765 bool run_irq_work = false;
1766
Eliad Peller402e48612011-05-13 11:57:09 +03001767 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1768 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001769 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001770
1771 /*
1772 * re-enable irq_work enqueuing, and call irq_work directly if
1773 * there is a pending work.
1774 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001775 spin_lock_irqsave(&wl->wl_lock, flags);
1776 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1777 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1778 run_irq_work = true;
1779 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001780
Eliad Peller4a859df2011-06-06 12:21:52 +03001781 if (run_irq_work) {
1782 wl1271_debug(DEBUG_MAC80211,
1783 "run postponed irq_work directly");
1784 wl1271_irq(0, wl);
1785 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001786 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001787 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001788 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001789
Eliad Peller402e48612011-05-13 11:57:09 +03001790 return 0;
1791}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001792#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001793
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001794static int wl1271_op_start(struct ieee80211_hw *hw)
1795{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001796 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1797
1798 /*
1799 * We have to delay the booting of the hardware because
1800 * we need to know the local MAC address before downloading and
1801 * initializing the firmware. The MAC address cannot be changed
1802 * after boot, and without the proper MAC address, the firmware
1803 * will not function properly.
1804 *
1805 * The MAC address is first known when the corresponding interface
1806 * is added. That is where we will initialize the hardware.
1807 */
1808
1809 return 0;
1810}
1811
1812static void wl1271_op_stop(struct ieee80211_hw *hw)
1813{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001814 struct wl1271 *wl = hw->priv;
1815 int i;
1816
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001817 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001818
1819 mutex_lock(&wl_list_mutex);
1820 list_del(&wl->list);
1821
1822 /*
1823 * this must be before the cancel_work calls below, so that the work
1824 * functions don't perform further work.
1825 */
1826 wl->state = WL1271_STATE_OFF;
1827 mutex_unlock(&wl_list_mutex);
1828
1829 wl1271_disable_interrupts(wl);
1830 wl1271_flush_deferred_work(wl);
1831 cancel_delayed_work_sync(&wl->scan_complete_work);
1832 cancel_work_sync(&wl->netstack_work);
1833 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001834 cancel_delayed_work_sync(&wl->elp_work);
1835
1836 /* let's notify MAC80211 about the remaining pending TX frames */
1837 wl12xx_tx_reset(wl, true);
1838 mutex_lock(&wl->mutex);
1839
1840 wl1271_power_off(wl);
1841
1842 wl->band = IEEE80211_BAND_2GHZ;
1843
1844 wl->rx_counter = 0;
1845 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1846 wl->tx_blocks_available = 0;
1847 wl->tx_allocated_blocks = 0;
1848 wl->tx_results_count = 0;
1849 wl->tx_packets_count = 0;
1850 wl->time_offset = 0;
1851 wl->vif = NULL;
1852 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1853 wl->ap_fw_ps_map = 0;
1854 wl->ap_ps_map = 0;
1855 wl->sched_scanning = false;
1856 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1857 memset(wl->links_map, 0, sizeof(wl->links_map));
1858 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1859 wl->active_sta_count = 0;
1860
1861 /* The system link is always allocated */
1862 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1863
1864 /*
1865 * this is performed after the cancel_work calls and the associated
1866 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1867 * get executed before all these vars have been reset.
1868 */
1869 wl->flags = 0;
1870
1871 wl->tx_blocks_freed = 0;
1872
1873 for (i = 0; i < NUM_TX_QUEUES; i++) {
1874 wl->tx_pkts_freed[i] = 0;
1875 wl->tx_allocated_pkts[i] = 0;
1876 }
1877
1878 wl1271_debugfs_reset(wl);
1879
1880 kfree(wl->fw_status);
1881 wl->fw_status = NULL;
1882 kfree(wl->tx_res_if);
1883 wl->tx_res_if = NULL;
1884 kfree(wl->target_mem_map);
1885 wl->target_mem_map = NULL;
1886
1887 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001888}
1889
Eliad Peller536129c82011-10-05 11:55:45 +02001890static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001891{
Eliad Peller536129c82011-10-05 11:55:45 +02001892 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001893 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001894 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001895 return WL1271_ROLE_P2P_GO;
1896 else
1897 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001898
1899 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001900 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001901 return WL1271_ROLE_P2P_CL;
1902 else
1903 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001904
Eliad Peller227e81e2011-08-14 13:17:26 +03001905 case BSS_TYPE_IBSS:
1906 return WL1271_ROLE_IBSS;
1907
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001908 default:
Eliad Peller536129c82011-10-05 11:55:45 +02001909 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001910 }
1911 return WL12XX_INVALID_ROLE_TYPE;
1912}
1913
Eliad Peller83587502011-10-10 10:12:53 +02001914static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001915{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001916 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1917
Eliad Peller48e93e42011-10-10 10:12:58 +02001918 /* clear everything but the persistent data */
1919 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001920
1921 switch (ieee80211_vif_type_p2p(vif)) {
1922 case NL80211_IFTYPE_P2P_CLIENT:
1923 wlvif->p2p = 1;
1924 /* fall-through */
1925 case NL80211_IFTYPE_STATION:
1926 wlvif->bss_type = BSS_TYPE_STA_BSS;
1927 break;
1928 case NL80211_IFTYPE_ADHOC:
1929 wlvif->bss_type = BSS_TYPE_IBSS;
1930 break;
1931 case NL80211_IFTYPE_P2P_GO:
1932 wlvif->p2p = 1;
1933 /* fall-through */
1934 case NL80211_IFTYPE_AP:
1935 wlvif->bss_type = BSS_TYPE_AP_BSS;
1936 break;
1937 default:
1938 wlvif->bss_type = MAX_BSS_TYPE;
1939 return -EOPNOTSUPP;
1940 }
1941
Eliad Peller0603d892011-10-05 11:55:51 +02001942 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001943 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001944 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001945
Eliad Pellere936bbe2011-10-05 11:55:56 +02001946 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1947 wlvif->bss_type == BSS_TYPE_IBSS) {
1948 /* init sta/ibss data */
1949 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
1950
1951 } else {
1952 /* init ap data */
1953 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1954 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
1955 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001956
Eliad Peller83587502011-10-10 10:12:53 +02001957 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1958 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001959 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001960 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001961 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001962 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1963
Eliad Peller9eb599e2011-10-10 10:12:59 +02001964 INIT_WORK(&wlvif->rx_streaming_enable_work,
1965 wl1271_rx_streaming_enable_work);
1966 INIT_WORK(&wlvif->rx_streaming_disable_work,
1967 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001968 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller876272142011-10-10 10:12:54 +02001969 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001970
Eliad Peller9eb599e2011-10-10 10:12:59 +02001971 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1972 (unsigned long) wlvif);
1973
Eliad Pellere936bbe2011-10-05 11:55:56 +02001974 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001975}
1976
Eliad Peller1d095472011-10-10 10:12:49 +02001977static bool wl12xx_init_fw(struct wl1271 *wl)
1978{
1979 int retries = WL1271_BOOT_RETRIES;
1980 bool booted = false;
1981 struct wiphy *wiphy = wl->hw->wiphy;
1982 int ret;
1983
1984 while (retries) {
1985 retries--;
1986 ret = wl1271_chip_wakeup(wl);
1987 if (ret < 0)
1988 goto power_off;
1989
1990 ret = wl1271_boot(wl);
1991 if (ret < 0)
1992 goto power_off;
1993
1994 ret = wl1271_hw_init(wl);
1995 if (ret < 0)
1996 goto irq_disable;
1997
1998 booted = true;
1999 break;
2000
2001irq_disable:
2002 mutex_unlock(&wl->mutex);
2003 /* Unlocking the mutex in the middle of handling is
2004 inherently unsafe. In this case we deem it safe to do,
2005 because we need to let any possibly pending IRQ out of
2006 the system (and while we are WL1271_STATE_OFF the IRQ
2007 work function will not do anything.) Also, any other
2008 possible concurrent operations will fail due to the
2009 current state, hence the wl1271 struct should be safe. */
2010 wl1271_disable_interrupts(wl);
2011 wl1271_flush_deferred_work(wl);
2012 cancel_work_sync(&wl->netstack_work);
2013 mutex_lock(&wl->mutex);
2014power_off:
2015 wl1271_power_off(wl);
2016 }
2017
2018 if (!booted) {
2019 wl1271_error("firmware boot failed despite %d retries",
2020 WL1271_BOOT_RETRIES);
2021 goto out;
2022 }
2023
2024 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2025
2026 /* update hw/fw version info in wiphy struct */
2027 wiphy->hw_version = wl->chip.id;
2028 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2029 sizeof(wiphy->fw_version));
2030
2031 /*
2032 * Now we know if 11a is supported (info from the NVS), so disable
2033 * 11a channels if not supported
2034 */
2035 if (!wl->enable_11a)
2036 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2037
2038 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2039 wl->enable_11a ? "" : "not ");
2040
2041 wl->state = WL1271_STATE_ON;
2042out:
2043 return booted;
2044}
2045
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002046static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2047 struct ieee80211_vif *vif)
2048{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002050 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002052 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002053 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002055 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002056 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057
2058 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002059 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002060 wl1271_debug(DEBUG_MAC80211,
2061 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002062 ret = -EBUSY;
2063 goto out;
2064 }
2065
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002066 /*
2067 * in some very corner case HW recovery scenarios its possible to
2068 * get here before __wl1271_op_remove_interface is complete, so
2069 * opt out if that is the case.
2070 */
2071 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
2072 ret = -EBUSY;
2073 goto out;
2074 }
2075
Eliad Peller83587502011-10-10 10:12:53 +02002076 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002077 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002078 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002079
Eliad Peller252efa42011-10-05 11:56:00 +02002080 wlvif->wl = wl;
Eliad Peller536129c82011-10-05 11:55:45 +02002081 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002082 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2083 ret = -EINVAL;
2084 goto out;
2085 }
Eliad Peller1d095472011-10-10 10:12:49 +02002086
Eliad Peller784f6942011-10-05 11:55:39 +02002087 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002088 * TODO: after the nvs issue will be solved, move this block
2089 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002090 */
Eliad Peller1d095472011-10-10 10:12:49 +02002091 if (wl->state == WL1271_STATE_OFF) {
2092 /*
2093 * we still need this in order to configure the fw
2094 * while uploading the nvs
2095 */
2096 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002097
Eliad Peller1d095472011-10-10 10:12:49 +02002098 booted = wl12xx_init_fw(wl);
2099 if (!booted) {
2100 ret = -EINVAL;
2101 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002102 }
Eliad Peller1d095472011-10-10 10:12:49 +02002103 }
Eliad Peller04e80792011-08-14 13:17:09 +03002104
Eliad Peller1d095472011-10-10 10:12:49 +02002105 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2106 wlvif->bss_type == BSS_TYPE_IBSS) {
2107 /*
2108 * The device role is a special role used for
2109 * rx and tx frames prior to association (as
2110 * the STA role can get packets only from
2111 * its associated bssid)
2112 */
Eliad Peller784f6942011-10-05 11:55:39 +02002113 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002114 WL1271_ROLE_DEVICE,
2115 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002116 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002117 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002118 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119
Eliad Peller1d095472011-10-10 10:12:49 +02002120 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2121 role_type, &wlvif->role_id);
2122 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002123 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002124
2125 ret = wl1271_init_vif_specific(wl, vif);
2126 if (ret < 0)
2127 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002128
2129 wl->vif = vif;
Eliad Peller876272142011-10-10 10:12:54 +02002130 list_add(&wlvif->list, &wl->wlvif_list);
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002131 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002132
2133 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2134 wl->ap_count++;
2135 else
2136 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002137out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 mutex_unlock(&wl->mutex);
2139
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002140 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002141 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002142 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002143 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 return ret;
2146}
2147
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002148static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +02002149 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002150 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151{
Eliad Peller536129c82011-10-05 11:55:45 +02002152 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002153 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002155 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002157 /* because of hardware recovery, we may get here twice */
2158 if (wl->state != WL1271_STATE_ON)
2159 return;
2160
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002161 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002163 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c82011-10-05 11:55:45 +02002164 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002165 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002166
Eliad Pellerbaf62772011-10-10 10:12:52 +02002167 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2168 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002169 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002170 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002171 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002172 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002173 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174 }
2175
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002176 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2177 /* disable active roles */
2178 ret = wl1271_ps_elp_wakeup(wl);
2179 if (ret < 0)
2180 goto deinit;
2181
Eliad Peller536129c82011-10-05 11:55:45 +02002182 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002183 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002184 if (ret < 0)
2185 goto deinit;
2186 }
2187
Eliad Peller0603d892011-10-05 11:55:51 +02002188 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002189 if (ret < 0)
2190 goto deinit;
2191
2192 wl1271_ps_elp_sleep(wl);
2193 }
2194deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002195 /* clear all hlids (except system_hlid) */
Eliad Peller154da672011-10-05 11:55:53 +02002196 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002197 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002198 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2199 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002200
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002201 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002202 wl1271_free_ap_keys(wl, wlvif);
Eliad Peller876272142011-10-10 10:12:54 +02002203 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002204 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002205 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002206 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002207
Eliad Pellera4e41302011-10-11 11:49:15 +02002208 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2209 wl->ap_count--;
2210 else
2211 wl->sta_count--;
2212
Eliad Pellerbaf62772011-10-10 10:12:52 +02002213 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002214 del_timer_sync(&wlvif->rx_streaming_timer);
2215 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2216 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002217 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002218
Eliad Pellerbaf62772011-10-10 10:12:52 +02002219 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002220}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002221
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002222static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2223 struct ieee80211_vif *vif)
2224{
2225 struct wl1271 *wl = hw->priv;
2226
2227 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002228 /*
2229 * wl->vif can be null here if someone shuts down the interface
2230 * just when hardware recovery has been started.
2231 */
2232 if (wl->vif) {
2233 WARN_ON(wl->vif != vif);
Eliad Peller536129c82011-10-05 11:55:45 +02002234 __wl1271_op_remove_interface(wl, vif, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002235 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002236
Juuso Oikarinen67353292010-11-18 15:19:02 +02002237 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002238 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239}
2240
Eliad Peller87fbcb02011-10-05 11:55:41 +02002241static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2242 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002243{
2244 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002245 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002246
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002247 /*
2248 * One of the side effects of the JOIN command is that is clears
2249 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2250 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002251 * Currently the only valid scenario for JOIN during association
2252 * is on roaming, in which case we will also be given new keys.
2253 * Keep the below message for now, unless it starts bothering
2254 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002255 */
2256 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2257 wl1271_info("JOIN while associated.");
2258
2259 if (set_assoc)
2260 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2261
Eliad Peller227e81e2011-08-14 13:17:26 +03002262 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002263 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002264 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002265 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002266 if (ret < 0)
2267 goto out;
2268
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002269 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2270 goto out;
2271
2272 /*
2273 * The join command disable the keep-alive mode, shut down its process,
2274 * and also clear the template config, so we need to reset it all after
2275 * the join. The acx_aid starts the keep-alive process, and the order
2276 * of the commands below is relevant.
2277 */
Eliad Peller0603d892011-10-05 11:55:51 +02002278 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002279 if (ret < 0)
2280 goto out;
2281
Eliad Peller0603d892011-10-05 11:55:51 +02002282 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002283 if (ret < 0)
2284 goto out;
2285
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002286 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002287 if (ret < 0)
2288 goto out;
2289
Eliad Peller0603d892011-10-05 11:55:51 +02002290 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2291 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002292 ACX_KEEP_ALIVE_TPL_VALID);
2293 if (ret < 0)
2294 goto out;
2295
2296out:
2297 return ret;
2298}
2299
Eliad Peller0603d892011-10-05 11:55:51 +02002300static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002301{
2302 int ret;
2303
Shahar Levi6d158ff2011-09-08 13:01:33 +03002304 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2305 wl12xx_cmd_stop_channel_switch(wl);
2306 ieee80211_chswitch_done(wl->vif, false);
2307 }
2308
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002309 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002310 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002311 if (ret < 0)
2312 goto out;
2313
Oz Krakowskib992c682011-06-26 10:36:02 +03002314 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002315 wlvif->tx_security_last_seq_lsb = 0;
2316 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002317
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002318out:
2319 return ret;
2320}
2321
Eliad Peller87fbcb02011-10-05 11:55:41 +02002322static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002323{
Eliad Peller83587502011-10-10 10:12:53 +02002324 wlvif->basic_rate_set = wlvif->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002325 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002326}
2327
Eliad Peller251c1772011-08-14 13:17:17 +03002328static bool wl12xx_is_roc(struct wl1271 *wl)
2329{
2330 u8 role_id;
2331
2332 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2333 if (role_id >= WL12XX_MAX_ROLES)
2334 return false;
2335
2336 return true;
2337}
2338
Eliad Peller87fbcb02011-10-05 11:55:41 +02002339static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2340 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002341{
2342 int ret;
2343
2344 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002345 /* no need to croc if we weren't busy (e.g. during boot) */
2346 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002347 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002348 if (ret < 0)
2349 goto out;
2350
Eliad Peller7edebf52011-10-05 11:55:52 +02002351 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002352 if (ret < 0)
2353 goto out;
2354 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002355 wlvif->rate_set =
2356 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2357 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002358 if (ret < 0)
2359 goto out;
2360 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002361 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002362 ACX_KEEP_ALIVE_TPL_INVALID);
2363 if (ret < 0)
2364 goto out;
2365 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2366 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002367 /* The current firmware only supports sched_scan in idle */
2368 if (wl->sched_scanning) {
2369 wl1271_scan_sched_scan_stop(wl);
2370 ieee80211_sched_scan_stopped(wl->hw);
2371 }
2372
Eliad Peller7edebf52011-10-05 11:55:52 +02002373 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002374 if (ret < 0)
2375 goto out;
2376
Eliad Peller7edebf52011-10-05 11:55:52 +02002377 ret = wl12xx_roc(wl, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002378 if (ret < 0)
2379 goto out;
2380 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2381 }
2382
2383out:
2384 return ret;
2385}
2386
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2388{
2389 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002390 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2391 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002392 struct ieee80211_conf *conf = &hw->conf;
2393 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002394 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395
2396 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2397
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002398 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2399 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 channel,
2401 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002402 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002403 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2404 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002406 /*
2407 * mac80211 will go to idle nearly immediately after transmitting some
2408 * frames, such as the deauth. To make sure those frames reach the air,
2409 * wait here until the TX queue is fully flushed.
2410 */
2411 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2412 (conf->flags & IEEE80211_CONF_IDLE))
2413 wl1271_tx_flush(wl);
2414
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002415 mutex_lock(&wl->mutex);
2416
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002417 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002418 /* we support configuring the channel and band while off */
2419 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2420 wl->band = conf->channel->band;
2421 wl->channel = channel;
2422 }
2423
Arik Nemtsov097f8822011-06-27 22:06:34 +03002424 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2425 wl->power_level = conf->power_level;
2426
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002427 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002428 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002429
Eliad Peller536129c82011-10-05 11:55:45 +02002430 is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002431
Ido Yariva6208652011-03-01 15:14:41 +02002432 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 if (ret < 0)
2434 goto out;
2435
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002436 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002437 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2438 ((wl->band != conf->channel->band) ||
2439 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002440 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002441 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002442 wl->band = conf->channel->band;
2443 wl->channel = channel;
2444
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002445 if (!is_ap) {
2446 /*
2447 * FIXME: the mac80211 should really provide a fixed
2448 * rate to use here. for now, just use the smallest
2449 * possible rate for the band as a fixed rate for
2450 * association frames and other control messages.
2451 */
2452 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002453 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002454
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002455 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002456 wl1271_tx_min_rate_get(wl,
2457 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002458 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002459 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002460 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002461 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002462
Eliad Peller251c1772011-08-14 13:17:17 +03002463 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2464 if (wl12xx_is_roc(wl)) {
2465 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002466 ret = wl12xx_croc(wl,
2467 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002468 if (ret < 0)
2469 goto out_sleep;
2470 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002471 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002472 if (ret < 0)
2473 wl1271_warning("cmd join on channel "
2474 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002475 } else {
2476 /*
2477 * change the ROC channel. do it only if we are
2478 * not idle. otherwise, CROC will be called
2479 * anyway.
2480 */
2481 if (wl12xx_is_roc(wl) &&
2482 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002483 ret = wl12xx_croc(wl,
2484 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002485 if (ret < 0)
2486 goto out_sleep;
2487
Eliad Peller7edebf52011-10-05 11:55:52 +02002488 ret = wl12xx_roc(wl,
2489 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002490 if (ret < 0)
2491 wl1271_warning("roc failed %d",
2492 ret);
2493 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002494 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002495 }
2496 }
2497
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002498 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002499 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002500 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002501 if (ret < 0)
2502 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002503 }
2504
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002505 /*
2506 * if mac80211 changes the PSM mode, make sure the mode is not
2507 * incorrectly changed after the pspoll failure active window.
2508 */
2509 if (changed & IEEE80211_CONF_CHANGE_PS)
2510 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2511
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002512 if (conf->flags & IEEE80211_CONF_PS &&
2513 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2514 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515
2516 /*
2517 * We enter PSM only if we're already associated.
2518 * If we're not, we'll enter it when joining an SSID,
2519 * through the bss_info_changed() hook.
2520 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002521 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002522 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002523 ret = wl1271_ps_set_mode(wl, wlvif,
2524 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002525 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002526 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002527 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002528 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002529 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002530
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002531 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002532
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002533 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002534 ret = wl1271_ps_set_mode(wl, wlvif,
2535 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002536 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 }
2538
2539 if (conf->power_level != wl->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002540 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002542 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543
2544 wl->power_level = conf->power_level;
2545 }
2546
2547out_sleep:
2548 wl1271_ps_elp_sleep(wl);
2549
2550out:
2551 mutex_unlock(&wl->mutex);
2552
2553 return ret;
2554}
2555
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002556struct wl1271_filter_params {
2557 bool enabled;
2558 int mc_list_length;
2559 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2560};
2561
Jiri Pirko22bedad32010-04-01 21:22:57 +00002562static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2563 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002564{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002565 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002566 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002567 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002568
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002569 if (unlikely(wl->state == WL1271_STATE_OFF))
2570 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002571
Juuso Oikarinen74441132009-10-13 12:47:53 +03002572 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002573 if (!fp) {
2574 wl1271_error("Out of memory setting filters.");
2575 return 0;
2576 }
2577
2578 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002579 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002580 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2581 fp->enabled = false;
2582 } else {
2583 fp->enabled = true;
2584 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002585 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002586 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002587 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002588 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002589 }
2590
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002591 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002592}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002593
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002594#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2595 FIF_ALLMULTI | \
2596 FIF_FCSFAIL | \
2597 FIF_BCN_PRBRESP_PROMISC | \
2598 FIF_CONTROL | \
2599 FIF_OTHER_BSS)
2600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002601static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2602 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002603 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002604{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002605 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002606 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002607 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
2608 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2609
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002610 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002611
Arik Nemtsov7d057862010-10-16 19:25:35 +02002612 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2613 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002615 mutex_lock(&wl->mutex);
2616
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002617 *total &= WL1271_SUPPORTED_FILTERS;
2618 changed &= WL1271_SUPPORTED_FILTERS;
2619
2620 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002621 goto out;
2622
Ido Yariva6208652011-03-01 15:14:41 +02002623 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002624 if (ret < 0)
2625 goto out;
2626
Eliad Peller536129c82011-10-05 11:55:45 +02002627 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
Arik Nemtsov7d057862010-10-16 19:25:35 +02002628 if (*total & FIF_ALLMULTI)
Eliad Peller0603d892011-10-05 11:55:51 +02002629 ret = wl1271_acx_group_address_tbl(wl, wlvif, false,
2630 NULL, 0);
Arik Nemtsov7d057862010-10-16 19:25:35 +02002631 else if (fp)
Eliad Peller0603d892011-10-05 11:55:51 +02002632 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2633 fp->enabled,
Arik Nemtsov7d057862010-10-16 19:25:35 +02002634 fp->mc_list,
2635 fp->mc_list_length);
2636 if (ret < 0)
2637 goto out_sleep;
2638 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002639
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002640 /*
2641 * the fw doesn't provide an api to configure the filters. instead,
2642 * the filters configuration is based on the active roles / ROC
2643 * state.
2644 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002645
2646out_sleep:
2647 wl1271_ps_elp_sleep(wl);
2648
2649out:
2650 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002651 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002652}
2653
Eliad Peller170d0e62011-10-05 11:56:06 +02002654static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2655 u8 id, u8 key_type, u8 key_size,
2656 const u8 *key, u8 hlid, u32 tx_seq_32,
2657 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002658{
2659 struct wl1271_ap_key *ap_key;
2660 int i;
2661
2662 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2663
2664 if (key_size > MAX_KEY_SIZE)
2665 return -EINVAL;
2666
2667 /*
2668 * Find next free entry in ap_keys. Also check we are not replacing
2669 * an existing key.
2670 */
2671 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002672 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002673 break;
2674
Eliad Peller170d0e62011-10-05 11:56:06 +02002675 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002676 wl1271_warning("trying to record key replacement");
2677 return -EINVAL;
2678 }
2679 }
2680
2681 if (i == MAX_NUM_KEYS)
2682 return -EBUSY;
2683
2684 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2685 if (!ap_key)
2686 return -ENOMEM;
2687
2688 ap_key->id = id;
2689 ap_key->key_type = key_type;
2690 ap_key->key_size = key_size;
2691 memcpy(ap_key->key, key, key_size);
2692 ap_key->hlid = hlid;
2693 ap_key->tx_seq_32 = tx_seq_32;
2694 ap_key->tx_seq_16 = tx_seq_16;
2695
Eliad Peller170d0e62011-10-05 11:56:06 +02002696 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002697 return 0;
2698}
2699
Eliad Peller170d0e62011-10-05 11:56:06 +02002700static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002701{
2702 int i;
2703
2704 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002705 kfree(wlvif->ap.recorded_keys[i]);
2706 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002707 }
2708}
2709
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002710static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002711{
2712 int i, ret = 0;
2713 struct wl1271_ap_key *key;
2714 bool wep_key_added = false;
2715
2716 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002717 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002718 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002719 break;
2720
Eliad Peller170d0e62011-10-05 11:56:06 +02002721 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002722 hlid = key->hlid;
2723 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002724 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002725
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002726 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 key->id, key->key_type,
2728 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002729 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002730 key->tx_seq_16);
2731 if (ret < 0)
2732 goto out;
2733
2734 if (key->key_type == KEY_WEP)
2735 wep_key_added = true;
2736 }
2737
2738 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002739 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002740 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002741 if (ret < 0)
2742 goto out;
2743 }
2744
2745out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002746 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002747 return ret;
2748}
2749
Eliad Peller536129c82011-10-05 11:55:45 +02002750static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2751 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002752 u8 key_size, const u8 *key, u32 tx_seq_32,
2753 u16 tx_seq_16, struct ieee80211_sta *sta)
2754{
2755 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002756 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002757
2758 if (is_ap) {
2759 struct wl1271_station *wl_sta;
2760 u8 hlid;
2761
2762 if (sta) {
2763 wl_sta = (struct wl1271_station *)sta->drv_priv;
2764 hlid = wl_sta->hlid;
2765 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002766 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 }
2768
2769 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2770 /*
2771 * We do not support removing keys after AP shutdown.
2772 * Pretend we do to make mac80211 happy.
2773 */
2774 if (action != KEY_ADD_OR_REPLACE)
2775 return 0;
2776
Eliad Peller170d0e62011-10-05 11:56:06 +02002777 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778 key_type, key_size,
2779 key, hlid, tx_seq_32,
2780 tx_seq_16);
2781 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002782 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783 id, key_type, key_size,
2784 key, hlid, tx_seq_32,
2785 tx_seq_16);
2786 }
2787
2788 if (ret < 0)
2789 return ret;
2790 } else {
2791 const u8 *addr;
2792 static const u8 bcast_addr[ETH_ALEN] = {
2793 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2794 };
2795
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002796 /*
2797 * A STA set to GEM cipher requires 2 tx spare blocks.
2798 * Return to default value when GEM cipher key is removed
2799 */
2800 if (key_type == KEY_GEM) {
2801 if (action == KEY_ADD_OR_REPLACE)
2802 wl->tx_spare_blocks = 2;
2803 else if (action == KEY_REMOVE)
2804 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2805 }
2806
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002807 addr = sta ? sta->addr : bcast_addr;
2808
2809 if (is_zero_ether_addr(addr)) {
2810 /* We dont support TX only encryption */
2811 return -EOPNOTSUPP;
2812 }
2813
2814 /* The wl1271 does not allow to remove unicast keys - they
2815 will be cleared automatically on next CMD_JOIN. Ignore the
2816 request silently, as we dont want the mac80211 to emit
2817 an error message. */
2818 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2819 return 0;
2820
Eliad Peller010d3d32011-08-14 13:17:31 +03002821 /* don't remove key if hlid was already deleted */
2822 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002823 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002824 return 0;
2825
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002826 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 id, key_type, key_size,
2828 key, addr, tx_seq_32,
2829 tx_seq_16);
2830 if (ret < 0)
2831 return ret;
2832
2833 /* the default WEP key needs to be configured at least once */
2834 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002835 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002836 wlvif->default_key,
2837 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002838 if (ret < 0)
2839 return ret;
2840 }
2841 }
2842
2843 return 0;
2844}
2845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2847 struct ieee80211_vif *vif,
2848 struct ieee80211_sta *sta,
2849 struct ieee80211_key_conf *key_conf)
2850{
2851 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002852 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002853 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002854 u32 tx_seq_32 = 0;
2855 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002856 u8 key_type;
2857
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002858 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2859
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002860 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002861 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002862 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002863 key_conf->keylen, key_conf->flags);
2864 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002866 mutex_lock(&wl->mutex);
2867
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002868 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2869 ret = -EAGAIN;
2870 goto out_unlock;
2871 }
2872
Ido Yariva6208652011-03-01 15:14:41 +02002873 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002874 if (ret < 0)
2875 goto out_unlock;
2876
Johannes Berg97359d12010-08-10 09:46:38 +02002877 switch (key_conf->cipher) {
2878 case WLAN_CIPHER_SUITE_WEP40:
2879 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880 key_type = KEY_WEP;
2881
2882 key_conf->hw_key_idx = key_conf->keyidx;
2883 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002884 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002885 key_type = KEY_TKIP;
2886
2887 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002888 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2889 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002890 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002891 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002892 key_type = KEY_AES;
2893
2894 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002895 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2896 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002898 case WL1271_CIPHER_SUITE_GEM:
2899 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002900 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2901 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002902 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002904 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905
2906 ret = -EOPNOTSUPP;
2907 goto out_sleep;
2908 }
2909
2910 switch (cmd) {
2911 case SET_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02002912 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002913 key_conf->keyidx, key_type,
2914 key_conf->keylen, key_conf->key,
2915 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916 if (ret < 0) {
2917 wl1271_error("Could not add or replace key");
2918 goto out_sleep;
2919 }
2920 break;
2921
2922 case DISABLE_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02002923 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002924 key_conf->keyidx, key_type,
2925 key_conf->keylen, key_conf->key,
2926 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002927 if (ret < 0) {
2928 wl1271_error("Could not remove key");
2929 goto out_sleep;
2930 }
2931 break;
2932
2933 default:
2934 wl1271_error("Unsupported key cmd 0x%x", cmd);
2935 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 break;
2937 }
2938
2939out_sleep:
2940 wl1271_ps_elp_sleep(wl);
2941
2942out_unlock:
2943 mutex_unlock(&wl->mutex);
2944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 return ret;
2946}
2947
2948static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002949 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950 struct cfg80211_scan_request *req)
2951{
2952 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002953 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 int ret;
2956 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002957 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958
2959 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2960
2961 if (req->n_ssids) {
2962 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002963 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 }
2965
2966 mutex_lock(&wl->mutex);
2967
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002968 if (wl->state == WL1271_STATE_OFF) {
2969 /*
2970 * We cannot return -EBUSY here because cfg80211 will expect
2971 * a call to ieee80211_scan_completed if we do - in this case
2972 * there won't be any call.
2973 */
2974 ret = -EAGAIN;
2975 goto out;
2976 }
2977
Ido Yariva6208652011-03-01 15:14:41 +02002978 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979 if (ret < 0)
2980 goto out;
2981
Eliad Peller251c1772011-08-14 13:17:17 +03002982 /* cancel ROC before scanning */
2983 if (wl12xx_is_roc(wl)) {
2984 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2985 /* don't allow scanning right now */
2986 ret = -EBUSY;
2987 goto out_sleep;
2988 }
Eliad Peller7edebf52011-10-05 11:55:52 +02002989 wl12xx_croc(wl, wlvif->dev_role_id);
2990 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002991 }
2992
Eliad Peller784f6942011-10-05 11:55:39 +02002993 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002994out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002995 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996out:
2997 mutex_unlock(&wl->mutex);
2998
2999 return ret;
3000}
3001
Eliad Peller73ecce32011-06-27 13:06:45 +03003002static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3003 struct ieee80211_vif *vif)
3004{
3005 struct wl1271 *wl = hw->priv;
3006 int ret;
3007
3008 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3009
3010 mutex_lock(&wl->mutex);
3011
3012 if (wl->state == WL1271_STATE_OFF)
3013 goto out;
3014
3015 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3016 goto out;
3017
3018 ret = wl1271_ps_elp_wakeup(wl);
3019 if (ret < 0)
3020 goto out;
3021
3022 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3023 ret = wl1271_scan_stop(wl);
3024 if (ret < 0)
3025 goto out_sleep;
3026 }
3027 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3028 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003029 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003030 wl->scan.req = NULL;
3031 ieee80211_scan_completed(wl->hw, true);
3032
3033out_sleep:
3034 wl1271_ps_elp_sleep(wl);
3035out:
3036 mutex_unlock(&wl->mutex);
3037
3038 cancel_delayed_work_sync(&wl->scan_complete_work);
3039}
3040
Luciano Coelho33c2c062011-05-10 14:46:02 +03003041static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3042 struct ieee80211_vif *vif,
3043 struct cfg80211_sched_scan_request *req,
3044 struct ieee80211_sched_scan_ies *ies)
3045{
3046 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003047 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003048 int ret;
3049
3050 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3051
3052 mutex_lock(&wl->mutex);
3053
3054 ret = wl1271_ps_elp_wakeup(wl);
3055 if (ret < 0)
3056 goto out;
3057
Eliad Peller536129c82011-10-05 11:55:45 +02003058 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003059 if (ret < 0)
3060 goto out_sleep;
3061
Eliad Peller536129c82011-10-05 11:55:45 +02003062 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003063 if (ret < 0)
3064 goto out_sleep;
3065
3066 wl->sched_scanning = true;
3067
3068out_sleep:
3069 wl1271_ps_elp_sleep(wl);
3070out:
3071 mutex_unlock(&wl->mutex);
3072 return ret;
3073}
3074
3075static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3076 struct ieee80211_vif *vif)
3077{
3078 struct wl1271 *wl = hw->priv;
3079 int ret;
3080
3081 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3082
3083 mutex_lock(&wl->mutex);
3084
3085 ret = wl1271_ps_elp_wakeup(wl);
3086 if (ret < 0)
3087 goto out;
3088
3089 wl1271_scan_sched_scan_stop(wl);
3090
3091 wl1271_ps_elp_sleep(wl);
3092out:
3093 mutex_unlock(&wl->mutex);
3094}
3095
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003096static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3097{
3098 struct wl1271 *wl = hw->priv;
3099 int ret = 0;
3100
3101 mutex_lock(&wl->mutex);
3102
3103 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3104 ret = -EAGAIN;
3105 goto out;
3106 }
3107
Ido Yariva6208652011-03-01 15:14:41 +02003108 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003109 if (ret < 0)
3110 goto out;
3111
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003112 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003113 if (ret < 0)
3114 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3115
3116 wl1271_ps_elp_sleep(wl);
3117
3118out:
3119 mutex_unlock(&wl->mutex);
3120
3121 return ret;
3122}
3123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003124static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3125{
3126 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003127 struct ieee80211_vif *vif = wl->vif;
3128 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003129 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003130
3131 mutex_lock(&wl->mutex);
3132
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003133 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3134 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003135 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003136 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003137
Ido Yariva6208652011-03-01 15:14:41 +02003138 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003139 if (ret < 0)
3140 goto out;
3141
Eliad Peller0603d892011-10-05 11:55:51 +02003142 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143 if (ret < 0)
3144 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3145
3146 wl1271_ps_elp_sleep(wl);
3147
3148out:
3149 mutex_unlock(&wl->mutex);
3150
3151 return ret;
3152}
3153
Eliad Peller1fe9f162011-10-05 11:55:48 +02003154static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003155 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003156{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003157 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003158 u8 ssid_len;
3159 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3160 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003161
Eliad Peller889cb362011-05-01 09:56:45 +03003162 if (!ptr) {
3163 wl1271_error("No SSID in IEs!");
3164 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003165 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003166
Eliad Peller889cb362011-05-01 09:56:45 +03003167 ssid_len = ptr[1];
3168 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3169 wl1271_error("SSID is too long!");
3170 return -EINVAL;
3171 }
3172
Eliad Peller1fe9f162011-10-05 11:55:48 +02003173 wlvif->ssid_len = ssid_len;
3174 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003175 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003176}
3177
Eliad Pellerd48055d2011-09-15 12:07:04 +03003178static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3179{
3180 int len;
3181 const u8 *next, *end = skb->data + skb->len;
3182 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3183 skb->len - ieoffset);
3184 if (!ie)
3185 return;
3186 len = ie[1] + 2;
3187 next = ie + len;
3188 memmove(ie, next, end - next);
3189 skb_trim(skb, skb->len - len);
3190}
3191
Eliad Peller26b4bf22011-09-15 12:07:05 +03003192static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3193 unsigned int oui, u8 oui_type,
3194 int ieoffset)
3195{
3196 int len;
3197 const u8 *next, *end = skb->data + skb->len;
3198 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3199 skb->data + ieoffset,
3200 skb->len - ieoffset);
3201 if (!ie)
3202 return;
3203 len = ie[1] + 2;
3204 next = ie + len;
3205 memmove(ie, next, end - next);
3206 skb_trim(skb, skb->len - len);
3207}
3208
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003209static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003210 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003211 u8 *probe_rsp_data,
3212 size_t probe_rsp_len,
3213 u32 rates)
3214{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003215 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3216 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003217 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3218 int ssid_ie_offset, ie_offset, templ_len;
3219 const u8 *ptr;
3220
3221 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003222 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003223 return wl1271_cmd_template_set(wl,
3224 CMD_TEMPL_AP_PROBE_RESPONSE,
3225 probe_rsp_data,
3226 probe_rsp_len, 0,
3227 rates);
3228
3229 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3230 wl1271_error("probe_rsp template too big");
3231 return -EINVAL;
3232 }
3233
3234 /* start searching from IE offset */
3235 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3236
3237 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3238 probe_rsp_len - ie_offset);
3239 if (!ptr) {
3240 wl1271_error("No SSID in beacon!");
3241 return -EINVAL;
3242 }
3243
3244 ssid_ie_offset = ptr - probe_rsp_data;
3245 ptr += (ptr[1] + 2);
3246
3247 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3248
3249 /* insert SSID from bss_conf */
3250 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3251 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3252 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3253 bss_conf->ssid, bss_conf->ssid_len);
3254 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3255
3256 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3257 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3258 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3259
3260 return wl1271_cmd_template_set(wl,
3261 CMD_TEMPL_AP_PROBE_RESPONSE,
3262 probe_rsp_templ,
3263 templ_len, 0,
3264 rates);
3265}
3266
Arik Nemtsove78a2872010-10-16 19:07:21 +02003267static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003268 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003269 struct ieee80211_bss_conf *bss_conf,
3270 u32 changed)
3271{
Eliad Peller0603d892011-10-05 11:55:51 +02003272 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003273 int ret = 0;
3274
3275 if (changed & BSS_CHANGED_ERP_SLOT) {
3276 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003277 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003278 else
Eliad Peller0603d892011-10-05 11:55:51 +02003279 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003280 if (ret < 0) {
3281 wl1271_warning("Set slot time failed %d", ret);
3282 goto out;
3283 }
3284 }
3285
3286 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3287 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003288 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003289 else
Eliad Peller0603d892011-10-05 11:55:51 +02003290 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003291 }
3292
3293 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3294 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003295 ret = wl1271_acx_cts_protect(wl, wlvif,
3296 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003297 else
Eliad Peller0603d892011-10-05 11:55:51 +02003298 ret = wl1271_acx_cts_protect(wl, wlvif,
3299 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003300 if (ret < 0) {
3301 wl1271_warning("Set ctsprotect failed %d", ret);
3302 goto out;
3303 }
3304 }
3305
3306out:
3307 return ret;
3308}
3309
3310static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3311 struct ieee80211_vif *vif,
3312 struct ieee80211_bss_conf *bss_conf,
3313 u32 changed)
3314{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003315 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003316 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003317 int ret = 0;
3318
3319 if ((changed & BSS_CHANGED_BEACON_INT)) {
3320 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3321 bss_conf->beacon_int);
3322
Eliad Peller6a899792011-10-05 11:55:58 +02003323 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003324 }
3325
3326 if ((changed & BSS_CHANGED_BEACON)) {
3327 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003328 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 int ieoffset = offsetof(struct ieee80211_mgmt,
3330 u.beacon.variable);
3331 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3332 u16 tmpl_id;
3333
3334 if (!beacon)
3335 goto out;
3336
3337 wl1271_debug(DEBUG_MASTER, "beacon updated");
3338
Eliad Peller1fe9f162011-10-05 11:55:48 +02003339 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003340 if (ret < 0) {
3341 dev_kfree_skb(beacon);
3342 goto out;
3343 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003344 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3346 CMD_TEMPL_BEACON;
3347 ret = wl1271_cmd_template_set(wl, tmpl_id,
3348 beacon->data,
3349 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003350 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003351 if (ret < 0) {
3352 dev_kfree_skb(beacon);
3353 goto out;
3354 }
3355
Eliad Pellerd48055d2011-09-15 12:07:04 +03003356 /* remove TIM ie from probe response */
3357 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3358
Eliad Peller26b4bf22011-09-15 12:07:05 +03003359 /*
3360 * remove p2p ie from probe response.
3361 * the fw reponds to probe requests that don't include
3362 * the p2p ie. probe requests with p2p ie will be passed,
3363 * and will be responded by the supplicant (the spec
3364 * forbids including the p2p ie when responding to probe
3365 * requests that didn't include it).
3366 */
3367 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3368 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3369
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 hdr = (struct ieee80211_hdr *) beacon->data;
3371 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3372 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003373 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003374 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003375 beacon->data,
3376 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003377 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003378 else
3379 ret = wl1271_cmd_template_set(wl,
3380 CMD_TEMPL_PROBE_RESPONSE,
3381 beacon->data,
3382 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003383 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 dev_kfree_skb(beacon);
3385 if (ret < 0)
3386 goto out;
3387 }
3388
3389out:
3390 return ret;
3391}
3392
3393/* AP mode changes */
3394static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003395 struct ieee80211_vif *vif,
3396 struct ieee80211_bss_conf *bss_conf,
3397 u32 changed)
3398{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003399 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003401
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3403 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003404
Eliad Peller87fbcb02011-10-05 11:55:41 +02003405 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003406 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003407 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003408 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003409
Eliad Peller87fbcb02011-10-05 11:55:41 +02003410 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003412 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003414 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003415
Eliad Peller784f6942011-10-05 11:55:39 +02003416 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003417 if (ret < 0)
3418 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003419 }
3420
Arik Nemtsove78a2872010-10-16 19:07:21 +02003421 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3422 if (ret < 0)
3423 goto out;
3424
3425 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3426 if (bss_conf->enable_beacon) {
3427 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003428 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003429 if (ret < 0)
3430 goto out;
3431
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003432 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003433 if (ret < 0)
3434 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003435
3436 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3437 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 }
3439 } else {
3440 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003441 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 if (ret < 0)
3443 goto out;
3444
3445 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3446 wl1271_debug(DEBUG_AP, "stopped AP");
3447 }
3448 }
3449 }
3450
Eliad Peller0603d892011-10-05 11:55:51 +02003451 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 if (ret < 0)
3453 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003454
3455 /* Handle HT information change */
3456 if ((changed & BSS_CHANGED_HT) &&
3457 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003458 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003459 bss_conf->ht_operation_mode);
3460 if (ret < 0) {
3461 wl1271_warning("Set ht information failed %d", ret);
3462 goto out;
3463 }
3464 }
3465
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466out:
3467 return;
3468}
3469
3470/* STA/IBSS mode changes */
3471static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3472 struct ieee80211_vif *vif,
3473 struct ieee80211_bss_conf *bss_conf,
3474 u32 changed)
3475{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003476 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003477 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003478 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003479 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003480 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003481 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003482 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003483 bool sta_exists = false;
3484 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003485
3486 if (is_ibss) {
3487 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3488 changed);
3489 if (ret < 0)
3490 goto out;
3491 }
3492
Eliad Peller227e81e2011-08-14 13:17:26 +03003493 if (changed & BSS_CHANGED_IBSS) {
3494 if (bss_conf->ibss_joined) {
3495 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3496 ibss_joined = true;
3497 } else {
3498 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3499 &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003500 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003501 wl12xx_cmd_role_start_dev(wl, wlvif);
3502 wl12xx_roc(wl, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003503 }
3504 }
3505 }
3506
3507 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003508 do_join = true;
3509
3510 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003511 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003512 do_join = true;
3513
Eliad Peller227e81e2011-08-14 13:17:26 +03003514 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003515 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3516 bss_conf->enable_beacon ? "enabled" : "disabled");
3517
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003518 do_join = true;
3519 }
3520
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003522 bool enable = false;
3523 if (bss_conf->cqm_rssi_thold)
3524 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003525 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003526 bss_conf->cqm_rssi_thold,
3527 bss_conf->cqm_rssi_hyst);
3528 if (ret < 0)
3529 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003530 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003531 }
3532
Eliad Pellercdf09492011-10-05 11:55:44 +02003533 if (changed & BSS_CHANGED_BSSID)
3534 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003535 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003536 if (ret < 0)
3537 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003538
Eliad Peller784f6942011-10-05 11:55:39 +02003539 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003540 if (ret < 0)
3541 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003542
Eliad Pellerfa287b82010-12-26 09:27:50 +01003543 /* Need to update the BSSID (for filtering etc) */
3544 do_join = true;
3545 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003546
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003547 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3548 rcu_read_lock();
3549 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3550 if (!sta)
3551 goto sta_not_found;
3552
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003553 /* save the supp_rates of the ap */
3554 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3555 if (sta->ht_cap.ht_supported)
3556 sta_rate_set |=
3557 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003558 sta_ht_cap = sta->ht_cap;
3559 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003560
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003561sta_not_found:
3562 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003563 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003564
Arik Nemtsove78a2872010-10-16 19:07:21 +02003565 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003566 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003567 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003568 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003569 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003570 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003571
Eliad Peller74ec8392011-10-05 11:56:02 +02003572 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003573
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003574 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003575 * use basic rates from AP, and determine lowest rate
3576 * to use with control frames.
3577 */
3578 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003579 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003580 wl1271_tx_enabled_rates_get(wl, rates,
3581 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003582 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003583 wl1271_tx_min_rate_get(wl,
3584 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003585 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003586 wlvif->rate_set =
3587 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003588 sta_rate_set,
3589 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003590 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003591 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003592 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003593
3594 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003595 * with wl1271, we don't need to update the
3596 * beacon_int and dtim_period, because the firmware
3597 * updates it by itself when the first beacon is
3598 * received after a join.
3599 */
Eliad Peller6840e372011-10-05 11:55:50 +02003600 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003601 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003602 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003603
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003604 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003605 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003606 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003607 dev_kfree_skb(wlvif->probereq);
3608 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003609 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003610 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003611 ieoffset = offsetof(struct ieee80211_mgmt,
3612 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003613 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003614
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003615 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003616 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003617 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003619 } else {
3620 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003621 bool was_assoc =
3622 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3623 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003624 bool was_ifup =
3625 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3626 &wl->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003627 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003628
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003629 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003630 dev_kfree_skb(wlvif->probereq);
3631 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003632
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003633 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003634 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003635
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003636 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003637 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003638 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003639 wl1271_tx_min_rate_get(wl,
3640 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003641 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003642 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003643 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003644
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003645 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003646 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003647
3648 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003649 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003650 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003651 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003652
3653 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003654 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003655 u32 conf_flags = wl->hw->conf.flags;
3656 /*
3657 * we might have to disable roc, if there was
3658 * no IF_OPER_UP notification.
3659 */
3660 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003661 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003662 if (ret < 0)
3663 goto out;
3664 }
3665 /*
3666 * (we also need to disable roc in case of
3667 * roaming on the same channel. until we will
3668 * have a better flow...)
3669 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003670 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3671 ret = wl12xx_croc(wl,
3672 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003673 if (ret < 0)
3674 goto out;
3675 }
3676
Eliad Peller0603d892011-10-05 11:55:51 +02003677 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003678 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003679 wl12xx_cmd_role_start_dev(wl, wlvif);
3680 wl12xx_roc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003681 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003682 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003683 }
3684 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003685
Eliad Pellerd192d262011-05-24 14:33:08 +03003686 if (changed & BSS_CHANGED_IBSS) {
3687 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3688 bss_conf->ibss_joined);
3689
3690 if (bss_conf->ibss_joined) {
3691 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003692 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003693 wl1271_tx_enabled_rates_get(wl, rates,
3694 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003695 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003696 wl1271_tx_min_rate_get(wl,
3697 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003698
Shahar Levi06b660e2011-09-05 13:54:36 +03003699 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003700 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3701 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003702 if (ret < 0)
3703 goto out;
3704 }
3705 }
3706
Eliad Peller0603d892011-10-05 11:55:51 +02003707 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003708 if (ret < 0)
3709 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003711 if (changed & BSS_CHANGED_ARP_FILTER) {
3712 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003713 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003714
Eliad Pellerc5312772010-12-09 11:31:27 +02003715 if (bss_conf->arp_addr_cnt == 1 &&
3716 bss_conf->arp_filter_enabled) {
3717 /*
3718 * The template should have been configured only upon
3719 * association. however, it seems that the correct ip
3720 * isn't being set (when sending), so we have to
3721 * reconfigure the template upon every ip change.
3722 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003723 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003724 if (ret < 0) {
3725 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003726 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003727 }
3728
Eliad Peller0603d892011-10-05 11:55:51 +02003729 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003730 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003731 addr);
3732 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003733 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003734
3735 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003736 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003737 }
3738
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003739 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003740 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003741 if (ret < 0) {
3742 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003743 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003744 }
Eliad Peller251c1772011-08-14 13:17:17 +03003745
3746 /* ROC until connected (after EAPOL exchange) */
3747 if (!is_ibss) {
Eliad Peller0603d892011-10-05 11:55:51 +02003748 ret = wl12xx_roc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003749 if (ret < 0)
3750 goto out;
3751
3752 wl1271_check_operstate(wl,
3753 ieee80211_get_operstate(vif));
3754 }
3755 /*
3756 * stop device role if started (we might already be in
3757 * STA role). TODO: make it better.
3758 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003759 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3760 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003761 if (ret < 0)
3762 goto out;
3763
Eliad Peller7edebf52011-10-05 11:55:52 +02003764 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003765 if (ret < 0)
3766 goto out;
3767 }
Eliad Peller05dba352011-08-23 16:37:01 +03003768
3769 /* If we want to go in PSM but we're not there yet */
3770 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3771 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3772 enum wl1271_cmd_ps_mode mode;
3773
3774 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003775 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003776 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003777 true);
3778 if (ret < 0)
3779 goto out;
3780 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003781 }
3782
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003783 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003784 if (sta_exists) {
3785 if ((changed & BSS_CHANGED_HT) &&
3786 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003787 ret = wl1271_acx_set_ht_capabilities(wl,
3788 &sta_ht_cap,
3789 true,
Eliad Peller154da672011-10-05 11:55:53 +02003790 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003791 if (ret < 0) {
3792 wl1271_warning("Set ht cap true failed %d",
3793 ret);
3794 goto out;
3795 }
3796 }
3797 /* handle new association without HT and disassociation */
3798 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003799 ret = wl1271_acx_set_ht_capabilities(wl,
3800 &sta_ht_cap,
3801 false,
Eliad Peller154da672011-10-05 11:55:53 +02003802 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003803 if (ret < 0) {
3804 wl1271_warning("Set ht cap false failed %d",
3805 ret);
3806 goto out;
3807 }
3808 }
3809 }
3810
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003811 /* Handle HT information change. Done after join. */
3812 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003813 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003814 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003815 bss_conf->ht_operation_mode);
3816 if (ret < 0) {
3817 wl1271_warning("Set ht information failed %d", ret);
3818 goto out;
3819 }
3820 }
3821
Arik Nemtsove78a2872010-10-16 19:07:21 +02003822out:
3823 return;
3824}
3825
3826static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3827 struct ieee80211_vif *vif,
3828 struct ieee80211_bss_conf *bss_conf,
3829 u32 changed)
3830{
3831 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003832 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3833 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003834 int ret;
3835
3836 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3837 (int)changed);
3838
3839 mutex_lock(&wl->mutex);
3840
3841 if (unlikely(wl->state == WL1271_STATE_OFF))
3842 goto out;
3843
Ido Yariva6208652011-03-01 15:14:41 +02003844 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003845 if (ret < 0)
3846 goto out;
3847
3848 if (is_ap)
3849 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3850 else
3851 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003853 wl1271_ps_elp_sleep(wl);
3854
3855out:
3856 mutex_unlock(&wl->mutex);
3857}
3858
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003859static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3860 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003861 const struct ieee80211_tx_queue_params *params)
3862{
3863 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003864 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003865 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003866 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003867
3868 mutex_lock(&wl->mutex);
3869
3870 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3871
Kalle Valo4695dc92010-03-18 12:26:38 +02003872 if (params->uapsd)
3873 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3874 else
3875 ps_scheme = CONF_PS_SCHEME_LEGACY;
3876
Arik Nemtsov488fc542010-10-16 20:33:45 +02003877 if (wl->state == WL1271_STATE_OFF) {
3878 /*
3879 * If the state is off, the parameters will be recorded and
3880 * configured on init. This happens in AP-mode.
3881 */
3882 struct conf_tx_ac_category *conf_ac =
3883 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3884 struct conf_tx_tid *conf_tid =
3885 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3886
3887 conf_ac->ac = wl1271_tx_get_queue(queue);
3888 conf_ac->cw_min = (u8)params->cw_min;
3889 conf_ac->cw_max = params->cw_max;
3890 conf_ac->aifsn = params->aifs;
3891 conf_ac->tx_op_limit = params->txop << 5;
3892
3893 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3894 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3895 conf_tid->tsid = wl1271_tx_get_queue(queue);
3896 conf_tid->ps_scheme = ps_scheme;
3897 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3898 conf_tid->apsd_conf[0] = 0;
3899 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003900 goto out;
3901 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003902
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003903 ret = wl1271_ps_elp_wakeup(wl);
3904 if (ret < 0)
3905 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003906
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003907 /*
3908 * the txop is confed in units of 32us by the mac80211,
3909 * we need us
3910 */
Eliad Peller0603d892011-10-05 11:55:51 +02003911 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003912 params->cw_min, params->cw_max,
3913 params->aifs, params->txop << 5);
3914 if (ret < 0)
3915 goto out_sleep;
3916
Eliad Peller0603d892011-10-05 11:55:51 +02003917 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003918 CONF_CHANNEL_TYPE_EDCF,
3919 wl1271_tx_get_queue(queue),
3920 ps_scheme, CONF_ACK_POLICY_LEGACY,
3921 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003922
3923out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003924 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003925
3926out:
3927 mutex_unlock(&wl->mutex);
3928
3929 return ret;
3930}
3931
Eliad Peller37a41b42011-09-21 14:06:11 +03003932static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3933 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003934{
3935
3936 struct wl1271 *wl = hw->priv;
3937 u64 mactime = ULLONG_MAX;
3938 int ret;
3939
3940 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3941
3942 mutex_lock(&wl->mutex);
3943
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003944 if (unlikely(wl->state == WL1271_STATE_OFF))
3945 goto out;
3946
Ido Yariva6208652011-03-01 15:14:41 +02003947 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003948 if (ret < 0)
3949 goto out;
3950
3951 ret = wl1271_acx_tsf_info(wl, &mactime);
3952 if (ret < 0)
3953 goto out_sleep;
3954
3955out_sleep:
3956 wl1271_ps_elp_sleep(wl);
3957
3958out:
3959 mutex_unlock(&wl->mutex);
3960 return mactime;
3961}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003962
John W. Linvilleece550d2010-07-28 16:41:06 -04003963static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3964 struct survey_info *survey)
3965{
3966 struct wl1271 *wl = hw->priv;
3967 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003968
John W. Linvilleece550d2010-07-28 16:41:06 -04003969 if (idx != 0)
3970 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003971
John W. Linvilleece550d2010-07-28 16:41:06 -04003972 survey->channel = conf->channel;
3973 survey->filled = SURVEY_INFO_NOISE_DBM;
3974 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003975
John W. Linvilleece550d2010-07-28 16:41:06 -04003976 return 0;
3977}
3978
Arik Nemtsov409622e2011-02-23 00:22:29 +02003979static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003980 struct wl12xx_vif *wlvif,
3981 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003982{
3983 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003984 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003985
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003986
3987 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003988 wl1271_warning("could not allocate HLID - too much stations");
3989 return -EBUSY;
3990 }
3991
3992 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003993 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
3994 if (ret < 0) {
3995 wl1271_warning("could not allocate HLID - too many links");
3996 return -EBUSY;
3997 }
3998
3999 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004000 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004001 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004002 return 0;
4003}
4004
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004005void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004006{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004007 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004008 return;
4009
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004010 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004011 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004012 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004013 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004014 __clear_bit(hlid, &wl->ap_ps_map);
4015 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004016 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004017 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004018}
4019
4020static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4021 struct ieee80211_vif *vif,
4022 struct ieee80211_sta *sta)
4023{
4024 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004025 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004026 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004027 int ret = 0;
4028 u8 hlid;
4029
4030 mutex_lock(&wl->mutex);
4031
4032 if (unlikely(wl->state == WL1271_STATE_OFF))
4033 goto out;
4034
Eliad Peller536129c82011-10-05 11:55:45 +02004035 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004036 goto out;
4037
4038 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4039
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004040 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004041 if (ret < 0)
4042 goto out;
4043
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004044 wl_sta = (struct wl1271_station *)sta->drv_priv;
4045 hlid = wl_sta->hlid;
4046
Ido Yariva6208652011-03-01 15:14:41 +02004047 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004048 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004049 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004050
Eliad Pellerc690ec82011-08-14 13:17:07 +03004051 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004052 if (ret < 0)
4053 goto out_sleep;
4054
Eliad Pellerb67476e2011-08-14 13:17:23 +03004055 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4056 if (ret < 0)
4057 goto out_sleep;
4058
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004059 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4060 if (ret < 0)
4061 goto out_sleep;
4062
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004063out_sleep:
4064 wl1271_ps_elp_sleep(wl);
4065
Arik Nemtsov409622e2011-02-23 00:22:29 +02004066out_free_sta:
4067 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004068 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004069
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004070out:
4071 mutex_unlock(&wl->mutex);
4072 return ret;
4073}
4074
4075static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4076 struct ieee80211_vif *vif,
4077 struct ieee80211_sta *sta)
4078{
4079 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004080 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004081 struct wl1271_station *wl_sta;
4082 int ret = 0, id;
4083
4084 mutex_lock(&wl->mutex);
4085
4086 if (unlikely(wl->state == WL1271_STATE_OFF))
4087 goto out;
4088
Eliad Peller536129c82011-10-05 11:55:45 +02004089 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004090 goto out;
4091
4092 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4093
4094 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095 id = wl_sta->hlid;
4096 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004097 goto out;
4098
Ido Yariva6208652011-03-01 15:14:41 +02004099 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004100 if (ret < 0)
4101 goto out;
4102
Eliad Pellerc690ec82011-08-14 13:17:07 +03004103 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004104 if (ret < 0)
4105 goto out_sleep;
4106
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004107 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004108
4109out_sleep:
4110 wl1271_ps_elp_sleep(wl);
4111
4112out:
4113 mutex_unlock(&wl->mutex);
4114 return ret;
4115}
4116
Luciano Coelho4623ec72011-03-21 19:26:41 +02004117static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4118 struct ieee80211_vif *vif,
4119 enum ieee80211_ampdu_mlme_action action,
4120 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4121 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004122{
4123 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004124 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004125 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004126 u8 hlid, *ba_bitmap;
4127
4128 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4129 tid);
4130
4131 /* sanity check - the fields in FW are only 8bits wide */
4132 if (WARN_ON(tid > 0xFF))
4133 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004134
4135 mutex_lock(&wl->mutex);
4136
4137 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4138 ret = -EAGAIN;
4139 goto out;
4140 }
4141
Eliad Peller536129c82011-10-05 11:55:45 +02004142 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004143 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004144 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004145 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004146 struct wl1271_station *wl_sta;
4147
4148 wl_sta = (struct wl1271_station *)sta->drv_priv;
4149 hlid = wl_sta->hlid;
4150 ba_bitmap = &wl->links[hlid].ba_bitmap;
4151 } else {
4152 ret = -EINVAL;
4153 goto out;
4154 }
4155
Ido Yariva6208652011-03-01 15:14:41 +02004156 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004157 if (ret < 0)
4158 goto out;
4159
Shahar Levi70559a02011-05-22 16:10:22 +03004160 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4161 tid, action);
4162
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004163 switch (action) {
4164 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004165 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004166 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004167 break;
4168 }
4169
4170 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4171 ret = -EBUSY;
4172 wl1271_error("exceeded max RX BA sessions");
4173 break;
4174 }
4175
4176 if (*ba_bitmap & BIT(tid)) {
4177 ret = -EINVAL;
4178 wl1271_error("cannot enable RX BA session on active "
4179 "tid: %d", tid);
4180 break;
4181 }
4182
4183 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4184 hlid);
4185 if (!ret) {
4186 *ba_bitmap |= BIT(tid);
4187 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004188 }
4189 break;
4190
4191 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004192 if (!(*ba_bitmap & BIT(tid))) {
4193 ret = -EINVAL;
4194 wl1271_error("no active RX BA session on tid: %d",
4195 tid);
4196 break;
4197 }
4198
4199 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4200 hlid);
4201 if (!ret) {
4202 *ba_bitmap &= ~BIT(tid);
4203 wl->ba_rx_session_count--;
4204 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004205 break;
4206
4207 /*
4208 * The BA initiator session management in FW independently.
4209 * Falling break here on purpose for all TX APDU commands.
4210 */
4211 case IEEE80211_AMPDU_TX_START:
4212 case IEEE80211_AMPDU_TX_STOP:
4213 case IEEE80211_AMPDU_TX_OPERATIONAL:
4214 ret = -EINVAL;
4215 break;
4216
4217 default:
4218 wl1271_error("Incorrect ampdu action id=%x\n", action);
4219 ret = -EINVAL;
4220 }
4221
4222 wl1271_ps_elp_sleep(wl);
4223
4224out:
4225 mutex_unlock(&wl->mutex);
4226
4227 return ret;
4228}
4229
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004230static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4231 struct ieee80211_vif *vif,
4232 const struct cfg80211_bitrate_mask *mask)
4233{
Eliad Peller83587502011-10-10 10:12:53 +02004234 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004235 struct wl1271 *wl = hw->priv;
4236 int i;
4237
4238 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4239 mask->control[NL80211_BAND_2GHZ].legacy,
4240 mask->control[NL80211_BAND_5GHZ].legacy);
4241
4242 mutex_lock(&wl->mutex);
4243
4244 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004245 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004246 wl1271_tx_enabled_rates_get(wl,
4247 mask->control[i].legacy,
4248 i);
4249 mutex_unlock(&wl->mutex);
4250
4251 return 0;
4252}
4253
Shahar Levi6d158ff2011-09-08 13:01:33 +03004254static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4255 struct ieee80211_channel_switch *ch_switch)
4256{
4257 struct wl1271 *wl = hw->priv;
4258 int ret;
4259
4260 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4261
4262 mutex_lock(&wl->mutex);
4263
4264 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4265 mutex_unlock(&wl->mutex);
4266 ieee80211_chswitch_done(wl->vif, false);
4267 return;
4268 }
4269
4270 ret = wl1271_ps_elp_wakeup(wl);
4271 if (ret < 0)
4272 goto out;
4273
4274 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4275
4276 if (!ret)
4277 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4278
4279 wl1271_ps_elp_sleep(wl);
4280
4281out:
4282 mutex_unlock(&wl->mutex);
4283}
4284
Arik Nemtsov33437892011-04-26 23:35:39 +03004285static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4286{
4287 struct wl1271 *wl = hw->priv;
4288 bool ret = false;
4289
4290 mutex_lock(&wl->mutex);
4291
4292 if (unlikely(wl->state == WL1271_STATE_OFF))
4293 goto out;
4294
4295 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004296 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004297out:
4298 mutex_unlock(&wl->mutex);
4299
4300 return ret;
4301}
4302
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004303/* can't be const, mac80211 writes to this */
4304static struct ieee80211_rate wl1271_rates[] = {
4305 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004306 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4307 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004308 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004309 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4310 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004311 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4312 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004313 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4314 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004315 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4316 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004317 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4318 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004319 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4320 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004321 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4322 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004323 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004324 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4325 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004326 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004327 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4328 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004329 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004330 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4331 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004332 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004333 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4334 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004335 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004336 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4337 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004338 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004339 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4340 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004341 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004342 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4343 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004344};
4345
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004346/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004347static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004348 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004349 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004350 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4351 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4352 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004353 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004354 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4355 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4356 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004357 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004358 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4359 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4360 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004361 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004362};
4363
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004364/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004365static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004366 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004367 7, /* CONF_HW_RXTX_RATE_MCS7 */
4368 6, /* CONF_HW_RXTX_RATE_MCS6 */
4369 5, /* CONF_HW_RXTX_RATE_MCS5 */
4370 4, /* CONF_HW_RXTX_RATE_MCS4 */
4371 3, /* CONF_HW_RXTX_RATE_MCS3 */
4372 2, /* CONF_HW_RXTX_RATE_MCS2 */
4373 1, /* CONF_HW_RXTX_RATE_MCS1 */
4374 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004375
4376 11, /* CONF_HW_RXTX_RATE_54 */
4377 10, /* CONF_HW_RXTX_RATE_48 */
4378 9, /* CONF_HW_RXTX_RATE_36 */
4379 8, /* CONF_HW_RXTX_RATE_24 */
4380
4381 /* TI-specific rate */
4382 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4383
4384 7, /* CONF_HW_RXTX_RATE_18 */
4385 6, /* CONF_HW_RXTX_RATE_12 */
4386 3, /* CONF_HW_RXTX_RATE_11 */
4387 5, /* CONF_HW_RXTX_RATE_9 */
4388 4, /* CONF_HW_RXTX_RATE_6 */
4389 2, /* CONF_HW_RXTX_RATE_5_5 */
4390 1, /* CONF_HW_RXTX_RATE_2 */
4391 0 /* CONF_HW_RXTX_RATE_1 */
4392};
4393
Shahar Levie8b03a22010-10-13 16:09:39 +02004394/* 11n STA capabilities */
4395#define HW_RX_HIGHEST_RATE 72
4396
Shahar Levi00d20102010-11-08 11:20:10 +00004397#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004398 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4399 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004400 .ht_supported = true, \
4401 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4402 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4403 .mcs = { \
4404 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4405 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4406 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4407 }, \
4408}
4409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410/* can't be const, mac80211 writes to this */
4411static struct ieee80211_supported_band wl1271_band_2ghz = {
4412 .channels = wl1271_channels,
4413 .n_channels = ARRAY_SIZE(wl1271_channels),
4414 .bitrates = wl1271_rates,
4415 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004416 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417};
4418
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004419/* 5 GHz data rates for WL1273 */
4420static struct ieee80211_rate wl1271_rates_5ghz[] = {
4421 { .bitrate = 60,
4422 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4423 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4424 { .bitrate = 90,
4425 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4426 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4427 { .bitrate = 120,
4428 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4430 { .bitrate = 180,
4431 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4432 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4433 { .bitrate = 240,
4434 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4435 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4436 { .bitrate = 360,
4437 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4438 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4439 { .bitrate = 480,
4440 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4441 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4442 { .bitrate = 540,
4443 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4444 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4445};
4446
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004447/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004448static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004449 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4450 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4451 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4452 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4453 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4454 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4455 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4456 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4457 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4458 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4459 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4460 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4461 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4462 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4463 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4464 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4465 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4466 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4467 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4468 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4469 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4470 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4471 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4472 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4473 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4474 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4475 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4476 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4477 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4478 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4479 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4480 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4481 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4482 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004483};
4484
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004485/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004486static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004487 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004488 7, /* CONF_HW_RXTX_RATE_MCS7 */
4489 6, /* CONF_HW_RXTX_RATE_MCS6 */
4490 5, /* CONF_HW_RXTX_RATE_MCS5 */
4491 4, /* CONF_HW_RXTX_RATE_MCS4 */
4492 3, /* CONF_HW_RXTX_RATE_MCS3 */
4493 2, /* CONF_HW_RXTX_RATE_MCS2 */
4494 1, /* CONF_HW_RXTX_RATE_MCS1 */
4495 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004496
4497 7, /* CONF_HW_RXTX_RATE_54 */
4498 6, /* CONF_HW_RXTX_RATE_48 */
4499 5, /* CONF_HW_RXTX_RATE_36 */
4500 4, /* CONF_HW_RXTX_RATE_24 */
4501
4502 /* TI-specific rate */
4503 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4504
4505 3, /* CONF_HW_RXTX_RATE_18 */
4506 2, /* CONF_HW_RXTX_RATE_12 */
4507 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4508 1, /* CONF_HW_RXTX_RATE_9 */
4509 0, /* CONF_HW_RXTX_RATE_6 */
4510 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4511 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4512 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4513};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004514
4515static struct ieee80211_supported_band wl1271_band_5ghz = {
4516 .channels = wl1271_channels_5ghz,
4517 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4518 .bitrates = wl1271_rates_5ghz,
4519 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004520 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004521};
4522
Tobias Klausera0ea9492010-05-20 10:38:11 +02004523static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004524 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4525 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4526};
4527
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528static const struct ieee80211_ops wl1271_ops = {
4529 .start = wl1271_op_start,
4530 .stop = wl1271_op_stop,
4531 .add_interface = wl1271_op_add_interface,
4532 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004533#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004534 .suspend = wl1271_op_suspend,
4535 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004536#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004537 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004538 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539 .configure_filter = wl1271_op_configure_filter,
4540 .tx = wl1271_op_tx,
4541 .set_key = wl1271_op_set_key,
4542 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004543 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004544 .sched_scan_start = wl1271_op_sched_scan_start,
4545 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004546 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004547 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004548 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004549 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004550 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004551 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004552 .sta_add = wl1271_op_sta_add,
4553 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004554 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004555 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004556 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004557 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004558 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004559};
4560
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004561
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004562u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004563{
4564 u8 idx;
4565
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004566 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004567
4568 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4569 wl1271_error("Illegal RX rate from HW: %d", rate);
4570 return 0;
4571 }
4572
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004573 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004574 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4575 wl1271_error("Unsupported RX rate from HW: %d", rate);
4576 return 0;
4577 }
4578
4579 return idx;
4580}
4581
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004582static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4583 struct device_attribute *attr,
4584 char *buf)
4585{
4586 struct wl1271 *wl = dev_get_drvdata(dev);
4587 ssize_t len;
4588
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004589 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004590
4591 mutex_lock(&wl->mutex);
4592 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4593 wl->sg_enabled);
4594 mutex_unlock(&wl->mutex);
4595
4596 return len;
4597
4598}
4599
4600static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4601 struct device_attribute *attr,
4602 const char *buf, size_t count)
4603{
4604 struct wl1271 *wl = dev_get_drvdata(dev);
4605 unsigned long res;
4606 int ret;
4607
Luciano Coelho6277ed62011-04-01 17:49:54 +03004608 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004609 if (ret < 0) {
4610 wl1271_warning("incorrect value written to bt_coex_mode");
4611 return count;
4612 }
4613
4614 mutex_lock(&wl->mutex);
4615
4616 res = !!res;
4617
4618 if (res == wl->sg_enabled)
4619 goto out;
4620
4621 wl->sg_enabled = res;
4622
4623 if (wl->state == WL1271_STATE_OFF)
4624 goto out;
4625
Ido Yariva6208652011-03-01 15:14:41 +02004626 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004627 if (ret < 0)
4628 goto out;
4629
4630 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4631 wl1271_ps_elp_sleep(wl);
4632
4633 out:
4634 mutex_unlock(&wl->mutex);
4635 return count;
4636}
4637
4638static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4639 wl1271_sysfs_show_bt_coex_state,
4640 wl1271_sysfs_store_bt_coex_state);
4641
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004642static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4643 struct device_attribute *attr,
4644 char *buf)
4645{
4646 struct wl1271 *wl = dev_get_drvdata(dev);
4647 ssize_t len;
4648
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004649 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004650
4651 mutex_lock(&wl->mutex);
4652 if (wl->hw_pg_ver >= 0)
4653 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4654 else
4655 len = snprintf(buf, len, "n/a\n");
4656 mutex_unlock(&wl->mutex);
4657
4658 return len;
4659}
4660
Gery Kahn6f07b722011-07-18 14:21:49 +03004661static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004662 wl1271_sysfs_show_hw_pg_ver, NULL);
4663
Ido Yariv95dac04f2011-06-06 14:57:06 +03004664static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4665 struct bin_attribute *bin_attr,
4666 char *buffer, loff_t pos, size_t count)
4667{
4668 struct device *dev = container_of(kobj, struct device, kobj);
4669 struct wl1271 *wl = dev_get_drvdata(dev);
4670 ssize_t len;
4671 int ret;
4672
4673 ret = mutex_lock_interruptible(&wl->mutex);
4674 if (ret < 0)
4675 return -ERESTARTSYS;
4676
4677 /* Let only one thread read the log at a time, blocking others */
4678 while (wl->fwlog_size == 0) {
4679 DEFINE_WAIT(wait);
4680
4681 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4682 &wait,
4683 TASK_INTERRUPTIBLE);
4684
4685 if (wl->fwlog_size != 0) {
4686 finish_wait(&wl->fwlog_waitq, &wait);
4687 break;
4688 }
4689
4690 mutex_unlock(&wl->mutex);
4691
4692 schedule();
4693 finish_wait(&wl->fwlog_waitq, &wait);
4694
4695 if (signal_pending(current))
4696 return -ERESTARTSYS;
4697
4698 ret = mutex_lock_interruptible(&wl->mutex);
4699 if (ret < 0)
4700 return -ERESTARTSYS;
4701 }
4702
4703 /* Check if the fwlog is still valid */
4704 if (wl->fwlog_size < 0) {
4705 mutex_unlock(&wl->mutex);
4706 return 0;
4707 }
4708
4709 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4710 len = min(count, (size_t)wl->fwlog_size);
4711 wl->fwlog_size -= len;
4712 memcpy(buffer, wl->fwlog, len);
4713
4714 /* Make room for new messages */
4715 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4716
4717 mutex_unlock(&wl->mutex);
4718
4719 return len;
4720}
4721
4722static struct bin_attribute fwlog_attr = {
4723 .attr = {.name = "fwlog", .mode = S_IRUSR},
4724 .read = wl1271_sysfs_read_fwlog,
4725};
4726
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004727int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004728{
4729 int ret;
4730
4731 if (wl->mac80211_registered)
4732 return 0;
4733
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004734 ret = wl1271_fetch_nvs(wl);
4735 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004736 /* NOTE: The wl->nvs->nvs element must be first, in
4737 * order to simplify the casting, we assume it is at
4738 * the beginning of the wl->nvs structure.
4739 */
4740 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004741
4742 wl->mac_addr[0] = nvs_ptr[11];
4743 wl->mac_addr[1] = nvs_ptr[10];
4744 wl->mac_addr[2] = nvs_ptr[6];
4745 wl->mac_addr[3] = nvs_ptr[5];
4746 wl->mac_addr[4] = nvs_ptr[4];
4747 wl->mac_addr[5] = nvs_ptr[3];
4748 }
4749
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004750 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4751
4752 ret = ieee80211_register_hw(wl->hw);
4753 if (ret < 0) {
4754 wl1271_error("unable to register mac80211 hw: %d", ret);
4755 return ret;
4756 }
4757
4758 wl->mac80211_registered = true;
4759
Eliad Pellerd60080a2010-11-24 12:53:16 +02004760 wl1271_debugfs_init(wl);
4761
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004762 register_netdevice_notifier(&wl1271_dev_notifier);
4763
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004764 wl1271_notice("loaded");
4765
4766 return 0;
4767}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004768EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004769
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004770void wl1271_unregister_hw(struct wl1271 *wl)
4771{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004772 if (wl->state == WL1271_STATE_PLT)
4773 __wl1271_plt_stop(wl);
4774
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004775 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004776 ieee80211_unregister_hw(wl->hw);
4777 wl->mac80211_registered = false;
4778
4779}
4780EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4781
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004782int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004783{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004784 static const u32 cipher_suites[] = {
4785 WLAN_CIPHER_SUITE_WEP40,
4786 WLAN_CIPHER_SUITE_WEP104,
4787 WLAN_CIPHER_SUITE_TKIP,
4788 WLAN_CIPHER_SUITE_CCMP,
4789 WL1271_CIPHER_SUITE_GEM,
4790 };
4791
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004792 /* The tx descriptor buffer and the TKIP space. */
4793 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4794 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004795
4796 /* unit us */
4797 /* FIXME: find a proper value */
4798 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004799 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004800
4801 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004802 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004803 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004804 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004805 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004806 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004807 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004808 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004809 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004810 IEEE80211_HW_AP_LINK_PS |
4811 IEEE80211_HW_AMPDU_AGGREGATION |
4812 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004813
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004814 wl->hw->wiphy->cipher_suites = cipher_suites;
4815 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4816
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004817 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004818 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4819 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004820 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004821 wl->hw->wiphy->max_sched_scan_ssids = 16;
4822 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004823 /*
4824 * Maximum length of elements in scanning probe request templates
4825 * should be the maximum length possible for a template, without
4826 * the IEEE80211 header of the template
4827 */
Eliad Peller154037d2011-08-14 13:17:12 +03004828 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004829 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004830
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004831 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4832 sizeof(struct ieee80211_header);
4833
Eliad Peller1ec23f72011-08-25 14:26:54 +03004834 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4835
Luciano Coelho4a31c112011-03-21 23:16:14 +02004836 /* make sure all our channels fit in the scanned_ch bitmask */
4837 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4838 ARRAY_SIZE(wl1271_channels_5ghz) >
4839 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004840 /*
4841 * We keep local copies of the band structs because we need to
4842 * modify them on a per-device basis.
4843 */
4844 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4845 sizeof(wl1271_band_2ghz));
4846 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4847 sizeof(wl1271_band_5ghz));
4848
4849 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4850 &wl->bands[IEEE80211_BAND_2GHZ];
4851 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4852 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004853
Kalle Valo12bd8942010-03-18 12:26:33 +02004854 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004855 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004856
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004857 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4858
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004859 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004860
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004861 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004862 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004863
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004864 wl->hw->max_rx_aggregation_subframes = 8;
4865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004866 return 0;
4867}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004868EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004869
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004870#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004871
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004872struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004873{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004874 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004875 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004876 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004877 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004878 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004879
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004880 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004882 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4883 if (!hw) {
4884 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004885 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004886 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004887 }
4888
Julia Lawall929ebd32010-05-15 23:16:39 +02004889 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004890 if (!plat_dev) {
4891 wl1271_error("could not allocate platform_device");
4892 ret = -ENOMEM;
4893 goto err_plat_alloc;
4894 }
4895
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004896 wl = hw->priv;
4897 memset(wl, 0, sizeof(*wl));
4898
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004899 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02004900 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004902 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004903 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004905 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004906 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004907 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4908
Ido Yariva6208652011-03-01 15:14:41 +02004909 skb_queue_head_init(&wl->deferred_rx_queue);
4910 skb_queue_head_init(&wl->deferred_tx_queue);
4911
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004912 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004913 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004914 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4915 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4916 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004917
Eliad Peller92ef8962011-06-07 12:50:46 +03004918 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4919 if (!wl->freezable_wq) {
4920 ret = -ENOMEM;
4921 goto err_hw;
4922 }
4923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004924 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004925 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004926 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004927 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004928 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004929 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004930 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004931 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004932 wl->ap_ps_map = 0;
4933 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004934 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004935 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004936 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004937 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004938 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004939 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03004940 wl->fwlog_size = 0;
4941 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004942
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004943 /* The system link is always allocated */
4944 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4945
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004946 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004947 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004948 wl->tx_frames[i] = NULL;
4949
4950 spin_lock_init(&wl->wl_lock);
4951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004952 wl->state = WL1271_STATE_OFF;
4953 mutex_init(&wl->mutex);
4954
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004955 /* Apply default driver configuration. */
4956 wl1271_conf_init(wl);
4957
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004958 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4959 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4960 if (!wl->aggr_buf) {
4961 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004962 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004963 }
4964
Ido Yariv990f5de2011-03-31 10:06:59 +02004965 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4966 if (!wl->dummy_packet) {
4967 ret = -ENOMEM;
4968 goto err_aggr;
4969 }
4970
Ido Yariv95dac04f2011-06-06 14:57:06 +03004971 /* Allocate one page for the FW log */
4972 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4973 if (!wl->fwlog) {
4974 ret = -ENOMEM;
4975 goto err_dummy_packet;
4976 }
4977
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004978 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004979 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004980 if (ret) {
4981 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004982 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004983 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004984 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004985
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004986 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004987 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004988 if (ret < 0) {
4989 wl1271_error("failed to create sysfs file bt_coex_state");
4990 goto err_platform;
4991 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004992
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004993 /* Create sysfs file to get HW PG version */
4994 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4995 if (ret < 0) {
4996 wl1271_error("failed to create sysfs file hw_pg_ver");
4997 goto err_bt_coex_state;
4998 }
4999
Ido Yariv95dac04f2011-06-06 14:57:06 +03005000 /* Create sysfs file for the FW log */
5001 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
5002 if (ret < 0) {
5003 wl1271_error("failed to create sysfs file fwlog");
5004 goto err_hw_pg_ver;
5005 }
5006
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005007 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005008
Ido Yariv95dac04f2011-06-06 14:57:06 +03005009err_hw_pg_ver:
5010 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5011
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005012err_bt_coex_state:
5013 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
5014
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005015err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005016 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005017
Ido Yariv95dac04f2011-06-06 14:57:06 +03005018err_fwlog:
5019 free_page((unsigned long)wl->fwlog);
5020
Ido Yariv990f5de2011-03-31 10:06:59 +02005021err_dummy_packet:
5022 dev_kfree_skb(wl->dummy_packet);
5023
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005024err_aggr:
5025 free_pages((unsigned long)wl->aggr_buf, order);
5026
Eliad Peller92ef8962011-06-07 12:50:46 +03005027err_wq:
5028 destroy_workqueue(wl->freezable_wq);
5029
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005030err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005031 wl1271_debugfs_exit(wl);
5032 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005033
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005034err_plat_alloc:
5035 ieee80211_free_hw(hw);
5036
5037err_hw_alloc:
5038
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005039 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005040}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005041EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005042
5043int wl1271_free_hw(struct wl1271 *wl)
5044{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005045 /* Unblock any fwlog readers */
5046 mutex_lock(&wl->mutex);
5047 wl->fwlog_size = -1;
5048 wake_up_interruptible_all(&wl->fwlog_waitq);
5049 mutex_unlock(&wl->mutex);
5050
5051 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005052
5053 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5054
5055 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005056 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005057 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005058 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005059 free_pages((unsigned long)wl->aggr_buf,
5060 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005061 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005062
5063 wl1271_debugfs_exit(wl);
5064
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005065 vfree(wl->fw);
5066 wl->fw = NULL;
5067 kfree(wl->nvs);
5068 wl->nvs = NULL;
5069
5070 kfree(wl->fw_status);
5071 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005072 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005073
5074 ieee80211_free_hw(wl->hw);
5075
5076 return 0;
5077}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005078EXPORT_SYMBOL_GPL(wl1271_free_hw);
5079
Guy Eilam491bbd62011-01-12 10:33:29 +01005080u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005081EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005082module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005083MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5084
Ido Yariv95dac04f2011-06-06 14:57:06 +03005085module_param_named(fwlog, fwlog_param, charp, 0);
5086MODULE_PARM_DESC(keymap,
5087 "FW logger options: continuous, ondemand, dbgpins or disable");
5088
Eliad Peller2a5bff02011-08-25 18:10:59 +03005089module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5090MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5091
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005092MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005093MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005094MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");