blob: 6b8a8a339f96ecf091151dd21e0c5d17136dc4a3 [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,
380 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200381static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200382
383
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200384static void wl1271_device_release(struct device *dev)
385{
386
387}
388
389static struct platform_device wl1271_device = {
390 .name = "wl1271",
391 .id = -1,
392
393 /* device model insists to have a release function */
394 .dev = {
395 .release = wl1271_device_release,
396 },
397};
398
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200399static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300400static LIST_HEAD(wl_list);
401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
403{
404 int ret;
405 if (operstate != IF_OPER_UP)
406 return 0;
407
408 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
409 return 0;
410
Eliad Pellerb67476e2011-08-14 13:17:23 +0300411 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300412 if (ret < 0)
413 return ret;
414
Eliad Peller251c1772011-08-14 13:17:17 +0300415 wl12xx_croc(wl, wl->role_id);
416
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300417 wl1271_info("Association completed.");
418 return 0;
419}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
421 void *arg)
422{
423 struct net_device *dev = arg;
424 struct wireless_dev *wdev;
425 struct wiphy *wiphy;
426 struct ieee80211_hw *hw;
427 struct wl1271 *wl;
428 struct wl1271 *wl_temp;
429 int ret = 0;
430
431 /* Check that this notification is for us. */
432 if (what != NETDEV_CHANGE)
433 return NOTIFY_DONE;
434
435 wdev = dev->ieee80211_ptr;
436 if (wdev == NULL)
437 return NOTIFY_DONE;
438
439 wiphy = wdev->wiphy;
440 if (wiphy == NULL)
441 return NOTIFY_DONE;
442
443 hw = wiphy_priv(wiphy);
444 if (hw == NULL)
445 return NOTIFY_DONE;
446
447 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200448 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300449 list_for_each_entry(wl, &wl_list, list) {
450 if (wl == wl_temp)
451 break;
452 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200453 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 if (wl != wl_temp)
455 return NOTIFY_DONE;
456
457 mutex_lock(&wl->mutex);
458
459 if (wl->state == WL1271_STATE_OFF)
460 goto out;
461
462 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
463 goto out;
464
Ido Yariva6208652011-03-01 15:14:41 +0200465 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300466 if (ret < 0)
467 goto out;
468
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300469 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300470
471 wl1271_ps_elp_sleep(wl);
472
473out:
474 mutex_unlock(&wl->mutex);
475
476 return NOTIFY_OK;
477}
478
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100479static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200480 struct regulatory_request *request)
481{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100482 struct ieee80211_supported_band *band;
483 struct ieee80211_channel *ch;
484 int i;
485
486 band = wiphy->bands[IEEE80211_BAND_5GHZ];
487 for (i = 0; i < band->n_channels; i++) {
488 ch = &band->channels[i];
489 if (ch->flags & IEEE80211_CHAN_DISABLED)
490 continue;
491
492 if (ch->flags & IEEE80211_CHAN_RADAR)
493 ch->flags |= IEEE80211_CHAN_NO_IBSS |
494 IEEE80211_CHAN_PASSIVE_SCAN;
495
496 }
497
498 return 0;
499}
500
Eliad Peller77ddaa12011-05-15 11:10:29 +0300501static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
502{
503 int ret = 0;
504
505 /* we should hold wl->mutex */
506 ret = wl1271_acx_ps_rx_streaming(wl, enable);
507 if (ret < 0)
508 goto out;
509
510 if (enable)
511 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
512 else
513 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
514out:
515 return ret;
516}
517
518/*
519 * this function is being called when the rx_streaming interval
520 * has beed changed or rx_streaming should be disabled
521 */
522int wl1271_recalc_rx_streaming(struct wl1271 *wl)
523{
524 int ret = 0;
525 int period = wl->conf.rx_streaming.interval;
526
527 /* don't reconfigure if rx_streaming is disabled */
528 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
529 goto out;
530
531 /* reconfigure/disable according to new streaming_period */
532 if (period &&
533 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
534 (wl->conf.rx_streaming.always ||
535 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
536 ret = wl1271_set_rx_streaming(wl, true);
537 else {
538 ret = wl1271_set_rx_streaming(wl, false);
539 /* don't cancel_work_sync since we might deadlock */
540 del_timer_sync(&wl->rx_streaming_timer);
541 }
542out:
543 return ret;
544}
545
546static void wl1271_rx_streaming_enable_work(struct work_struct *work)
547{
548 int ret;
549 struct wl1271 *wl =
550 container_of(work, struct wl1271, rx_streaming_enable_work);
551
552 mutex_lock(&wl->mutex);
553
554 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
555 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
556 (!wl->conf.rx_streaming.always &&
557 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
558 goto out;
559
560 if (!wl->conf.rx_streaming.interval)
561 goto out;
562
563 ret = wl1271_ps_elp_wakeup(wl);
564 if (ret < 0)
565 goto out;
566
567 ret = wl1271_set_rx_streaming(wl, true);
568 if (ret < 0)
569 goto out_sleep;
570
571 /* stop it after some time of inactivity */
572 mod_timer(&wl->rx_streaming_timer,
573 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
574
575out_sleep:
576 wl1271_ps_elp_sleep(wl);
577out:
578 mutex_unlock(&wl->mutex);
579}
580
581static void wl1271_rx_streaming_disable_work(struct work_struct *work)
582{
583 int ret;
584 struct wl1271 *wl =
585 container_of(work, struct wl1271, rx_streaming_disable_work);
586
587 mutex_lock(&wl->mutex);
588
589 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
590 goto out;
591
592 ret = wl1271_ps_elp_wakeup(wl);
593 if (ret < 0)
594 goto out;
595
596 ret = wl1271_set_rx_streaming(wl, false);
597 if (ret)
598 goto out_sleep;
599
600out_sleep:
601 wl1271_ps_elp_sleep(wl);
602out:
603 mutex_unlock(&wl->mutex);
604}
605
606static void wl1271_rx_streaming_timer(unsigned long data)
607{
608 struct wl1271 *wl = (struct wl1271 *)data;
609 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
610}
611
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300612static void wl1271_conf_init(struct wl1271 *wl)
613{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
615 /*
616 * This function applies the default configuration to the driver. This
617 * function is invoked upon driver load (spi probe.)
618 *
619 * The configuration is stored in a run-time structure in order to
620 * facilitate for run-time adjustment of any of the parameters. Making
621 * changes to the configuration structure will apply the new values on
622 * the next interface up (wl1271_op_start.)
623 */
624
625 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300626 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
Ido Yariv95dac04f2011-06-06 14:57:06 +0300628 /* Adjust settings according to optional module parameters */
629 if (fwlog_param) {
630 if (!strcmp(fwlog_param, "continuous")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 } else if (!strcmp(fwlog_param, "ondemand")) {
633 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
634 } else if (!strcmp(fwlog_param, "dbgpins")) {
635 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
636 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
637 } else if (!strcmp(fwlog_param, "disable")) {
638 wl->conf.fwlog.mem_blocks = 0;
639 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
640 } else {
641 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
642 }
643 }
644}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646static int wl1271_plt_init(struct wl1271 *wl)
647{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200648 struct conf_tx_ac_category *conf_ac;
649 struct conf_tx_tid *conf_tid;
650 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Shahar Levi49d750ca2011-03-06 16:32:09 +0200652 if (wl->chip.id == CHIP_ID_1283_PG20)
653 ret = wl128x_cmd_general_parms(wl);
654 else
655 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200656 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200657 return ret;
658
Shahar Levi49d750ca2011-03-06 16:32:09 +0200659 if (wl->chip.id == CHIP_ID_1283_PG20)
660 ret = wl128x_cmd_radio_parms(wl);
661 else
662 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200663 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200664 return ret;
665
Shahar Levi49d750ca2011-03-06 16:32:09 +0200666 if (wl->chip.id != CHIP_ID_1283_PG20) {
667 ret = wl1271_cmd_ext_radio_parms(wl);
668 if (ret < 0)
669 return ret;
670 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200671 if (ret < 0)
672 return ret;
673
Shahar Levi48a61472011-03-06 16:32:08 +0200674 /* Chip-specific initializations */
675 ret = wl1271_chip_specific_init(wl);
676 if (ret < 0)
677 return ret;
678
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200679 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 /* PHY layer config */
688 ret = wl1271_init_phy_config(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 ret = wl1271_acx_dco_itrim_params(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200697 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Bluetooth WLAN coexistence */
702 ret = wl1271_init_pta(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
Shahar Leviff868432011-04-11 15:41:46 +0300706 /* FM WLAN coexistence */
707 ret = wl1271_acx_fm_coex(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Luciano Coelho12419cc2010-02-18 13:25:44 +0200711 /* Energy detection */
712 ret = wl1271_init_energy_detection(wl);
713 if (ret < 0)
714 goto out_free_memmap;
715
Eliad Peller7f0979882011-08-14 13:17:06 +0300716 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho12419cc2010-02-18 13:25:44 +0200720 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100721 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 if (ret < 0)
723 goto out_free_memmap;
724
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200725 /* Default TID/AC configuration */
726 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200727 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200728 conf_ac = &wl->conf.tx.ac_conf[i];
729 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
730 conf_ac->cw_max, conf_ac->aifsn,
731 conf_ac->tx_op_limit);
732 if (ret < 0)
733 goto out_free_memmap;
734
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid = &wl->conf.tx.tid_conf[i];
736 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
737 conf_tid->channel_type,
738 conf_tid->tsid,
739 conf_tid->ps_scheme,
740 conf_tid->ack_policy,
741 conf_tid->apsd_conf[0],
742 conf_tid->apsd_conf[1]);
743 if (ret < 0)
744 goto out_free_memmap;
745 }
746
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200748 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 goto out_free_memmap;
751
752 /* Configure for CAM power saving (ie. always active) */
753 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
754 if (ret < 0)
755 goto out_free_memmap;
756
757 /* configure PM */
758 ret = wl1271_acx_pm_config(wl);
759 if (ret < 0)
760 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763
764 out_free_memmap:
765 kfree(wl->target_mem_map);
766 wl->target_mem_map = NULL;
767
768 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769}
770
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300771static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
775 /* only regulate station links */
776 if (hlid < WL1271_AP_STA_HLID_START)
777 return;
778
779 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300780 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781
782 /*
783 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300784 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300786 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787 wl1271_ps_link_end(wl, hlid);
788
Arik Nemtsovda032092011-08-25 12:43:15 +0300789 /*
790 * Start high-level PS if the STA is asleep with enough blocks in FW.
791 * Make an exception if this is the only connected station. In this
792 * case FW-memory congestion is not a problem.
793 */
794 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200795 wl1271_ps_link_start(wl, hlid, true);
796}
797
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300798bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
799{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300800 int id;
801
802 /* global/broadcast "stations" are always active */
803 if (hlid < WL1271_AP_STA_HLID_START)
804 return true;
805
806 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300807 return test_bit(id, wl->ap_hlid_map);
808}
809
810static void wl12xx_irq_update_links_status(struct wl1271 *wl,
811 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812{
813 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300814 u8 hlid, cnt;
815
816 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
818 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
819 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
820 wl1271_debug(DEBUG_PSM,
821 "link ps prev 0x%x cur 0x%x changed 0x%x",
822 wl->ap_fw_ps_map, cur_fw_ps_map,
823 wl->ap_fw_ps_map ^ cur_fw_ps_map);
824
825 wl->ap_fw_ps_map = cur_fw_ps_map;
826 }
827
828 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300829 if (!wl1271_is_active_sta(wl, hlid))
830 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200831
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300832 cnt = status->tx_lnk_free_pkts[hlid] -
833 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200834
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300835 wl->links[hlid].prev_freed_pkts =
836 status->tx_lnk_free_pkts[hlid];
837 wl->links[hlid].allocated_pkts -= cnt;
838
839 wl12xx_irq_ps_regulate_link(wl, hlid,
840 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200841 }
842}
843
Eliad Peller4d56ad92011-08-14 13:17:05 +0300844static void wl12xx_fw_status(struct wl1271 *wl,
845 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200847 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200848 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300849 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300850 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
855 "drv_rx_counter = %d, tx_results_counter = %d)",
856 status->intr,
857 status->fw_rx_counter,
858 status->drv_rx_counter,
859 status->tx_results_counter);
860
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300861 for (i = 0; i < NUM_TX_QUEUES; i++) {
862 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300863 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300864 (status->tx_released_pkts[i] -
865 wl->tx_pkts_freed[i]) & 0xff;
866
867 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
868 }
869
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300870 /* prevent wrap-around in total blocks counter */
871 if (likely(wl->tx_blocks_freed <=
872 le32_to_cpu(status->total_released_blks)))
873 freed_blocks = le32_to_cpu(status->total_released_blks) -
874 wl->tx_blocks_freed;
875 else
876 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
877 le32_to_cpu(status->total_released_blks);
878
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200880
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300881 wl->tx_allocated_blocks -= freed_blocks;
882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200884
Eliad Peller4d56ad92011-08-14 13:17:05 +0300885 /*
886 * The FW might change the total number of TX memblocks before
887 * we get a notification about blocks being released. Thus, the
888 * available blocks calculation might yield a temporary result
889 * which is lower than the actual available blocks. Keeping in
890 * mind that only blocks that were allocated can be moved from
891 * TX to RX, tx_blocks_available should never decrease here.
892 */
893 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
894 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
Ido Yariva5225502010-10-12 14:49:10 +0200896 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200897 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200898 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
Eliad Peller4d56ad92011-08-14 13:17:05 +0300900 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300901 if (wl->bss_type == BSS_TYPE_AP_BSS)
902 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300903
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200905 getnstimeofday(&ts);
906 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
907 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908}
909
Ido Yariva6208652011-03-01 15:14:41 +0200910static void wl1271_flush_deferred_work(struct wl1271 *wl)
911{
912 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Ido Yariva6208652011-03-01 15:14:41 +0200914 /* Pass all received frames to the network stack */
915 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
916 ieee80211_rx_ni(wl->hw, skb);
917
918 /* Return sent skbs to the network stack */
919 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300920 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200921}
922
923static void wl1271_netstack_work(struct work_struct *work)
924{
925 struct wl1271 *wl =
926 container_of(work, struct wl1271, netstack_work);
927
928 do {
929 wl1271_flush_deferred_work(wl);
930 } while (skb_queue_len(&wl->deferred_rx_queue));
931}
932
933#define WL1271_IRQ_MAX_LOOPS 256
934
935irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300938 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200939 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200940 struct wl1271 *wl = (struct wl1271 *)cookie;
941 bool done = false;
942 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200943 unsigned long flags;
944
945 /* TX might be handled here, avoid redundant work */
946 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
947 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948
Ido Yariv341b7cd2011-03-31 10:07:01 +0200949 /*
950 * In case edge triggered interrupt must be used, we cannot iterate
951 * more than once without introducing race conditions with the hardirq.
952 */
953 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
954 loopcount = 1;
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 mutex_lock(&wl->mutex);
957
958 wl1271_debug(DEBUG_IRQ, "IRQ work");
959
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 goto out;
962
Ido Yariva6208652011-03-01 15:14:41 +0200963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 if (ret < 0)
965 goto out;
966
Ido Yariva6208652011-03-01 15:14:41 +0200967 while (!done && loopcount--) {
968 /*
969 * In order to avoid a race with the hardirq, clear the flag
970 * before acknowledging the chip. Since the mutex is held,
971 * wl1271_ps_elp_wakeup cannot be called concurrently.
972 */
973 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
974 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975
Eliad Peller4d56ad92011-08-14 13:17:05 +0300976 wl12xx_fw_status(wl, wl->fw_status);
977 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200978 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200979 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200980 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981 continue;
982 }
983
Eliad Pellerccc83b02010-10-27 14:09:57 +0200984 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
985 wl1271_error("watchdog interrupt received! "
986 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300987 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200988
989 /* restarting the chip. ignore any other interrupt. */
990 goto out;
991 }
992
Ido Yariva6208652011-03-01 15:14:41 +0200993 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200994 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
995
Eliad Peller4d56ad92011-08-14 13:17:05 +0300996 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200997
Ido Yariva5225502010-10-12 14:49:10 +0200998 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200999 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001000 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001001 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001003 /*
1004 * In order to avoid starvation of the TX path,
1005 * call the work function directly.
1006 */
1007 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001008 } else {
1009 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001010 }
1011
Ido Yariv8aad2462011-03-01 15:14:38 +02001012 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001013 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001014 (wl->tx_results_count & 0xff))
1015 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001016
1017 /* Make sure the deferred queues don't get too long */
1018 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1019 skb_queue_len(&wl->deferred_rx_queue);
1020 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1021 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001022 }
1023
1024 if (intr & WL1271_ACX_INTR_EVENT_A) {
1025 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1026 wl1271_event_handle(wl, 0);
1027 }
1028
1029 if (intr & WL1271_ACX_INTR_EVENT_B) {
1030 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1031 wl1271_event_handle(wl, 1);
1032 }
1033
1034 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1035 wl1271_debug(DEBUG_IRQ,
1036 "WL1271_ACX_INTR_INIT_COMPLETE");
1037
1038 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1039 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 wl1271_ps_elp_sleep(wl);
1043
1044out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001045 spin_lock_irqsave(&wl->wl_lock, flags);
1046 /* In case TX was not handled here, queue TX work */
1047 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1048 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001049 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001050 ieee80211_queue_work(wl->hw, &wl->tx_work);
1051 spin_unlock_irqrestore(&wl->wl_lock, flags);
1052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001054
1055 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056}
Ido Yariva6208652011-03-01 15:14:41 +02001057EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059static int wl1271_fetch_firmware(struct wl1271 *wl)
1060{
1061 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 int ret;
1064
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001065 if (wl->chip.id == CHIP_ID_1283_PG20)
1066 fw_name = WL128X_FW_NAME;
1067 else
1068 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069
1070 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1071
1072 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
1074 if (ret < 0) {
1075 wl1271_error("could not get firmware: %d", ret);
1076 return ret;
1077 }
1078
1079 if (fw->size % 4) {
1080 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1081 fw->size);
1082 ret = -EILSEQ;
1083 goto out;
1084 }
1085
Arik Nemtsov166d5042010-10-16 21:44:57 +02001086 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001088 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089
1090 if (!wl->fw) {
1091 wl1271_error("could not allocate memory for the firmware");
1092 ret = -ENOMEM;
1093 goto out;
1094 }
1095
1096 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 ret = 0;
1098
1099out:
1100 release_firmware(fw);
1101
1102 return ret;
1103}
1104
1105static int wl1271_fetch_nvs(struct wl1271 *wl)
1106{
1107 const struct firmware *fw;
1108 int ret;
1109
Shahar Levi5aa42342011-03-06 16:32:07 +02001110 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 if (ret < 0) {
1113 wl1271_error("could not get nvs file: %d", ret);
1114 return ret;
1115 }
1116
Shahar Levibc765bf2011-03-06 16:32:10 +02001117 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001118
1119 if (!wl->nvs) {
1120 wl1271_error("could not allocate memory for the nvs file");
1121 ret = -ENOMEM;
1122 goto out;
1123 }
1124
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001125 wl->nvs_len = fw->size;
1126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127out:
1128 release_firmware(fw);
1129
1130 return ret;
1131}
1132
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001133void wl12xx_queue_recovery_work(struct wl1271 *wl)
1134{
1135 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1136 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1137}
1138
Ido Yariv95dac04f2011-06-06 14:57:06 +03001139size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1140{
1141 size_t len = 0;
1142
1143 /* The FW log is a length-value list, find where the log end */
1144 while (len < maxlen) {
1145 if (memblock[len] == 0)
1146 break;
1147 if (len + memblock[len] + 1 > maxlen)
1148 break;
1149 len += memblock[len] + 1;
1150 }
1151
1152 /* Make sure we have enough room */
1153 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1154
1155 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1156 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1157 wl->fwlog_size += len;
1158
1159 return len;
1160}
1161
1162static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1163{
1164 u32 addr;
1165 u32 first_addr;
1166 u8 *block;
1167
1168 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1169 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1170 (wl->conf.fwlog.mem_blocks == 0))
1171 return;
1172
1173 wl1271_info("Reading FW panic log");
1174
1175 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1176 if (!block)
1177 return;
1178
1179 /*
1180 * Make sure the chip is awake and the logger isn't active.
1181 * This might fail if the firmware hanged.
1182 */
1183 if (!wl1271_ps_elp_wakeup(wl))
1184 wl12xx_cmd_stop_fwlog(wl);
1185
1186 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 wl12xx_fw_status(wl, wl->fw_status);
1188 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001189 if (!first_addr)
1190 goto out;
1191
1192 /* Traverse the memory blocks linked list */
1193 addr = first_addr;
1194 do {
1195 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1196 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1197 false);
1198
1199 /*
1200 * Memory blocks are linked to one another. The first 4 bytes
1201 * of each memory block hold the hardware address of the next
1202 * one. The last memory block points to the first one.
1203 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001204 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001205 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1206 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1207 break;
1208 } while (addr && (addr != first_addr));
1209
1210 wake_up_interruptible(&wl->fwlog_waitq);
1211
1212out:
1213 kfree(block);
1214}
1215
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216static void wl1271_recovery_work(struct work_struct *work)
1217{
1218 struct wl1271 *wl =
1219 container_of(work, struct wl1271, recovery_work);
1220
1221 mutex_lock(&wl->mutex);
1222
1223 if (wl->state != WL1271_STATE_ON)
1224 goto out;
1225
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001226 /* Avoid a recursive recovery */
1227 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1228
Ido Yariv95dac04f2011-06-06 14:57:06 +03001229 wl12xx_read_fwlog_panic(wl);
1230
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001231 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1232 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001233
Eliad Peller2a5bff02011-08-25 18:10:59 +03001234 BUG_ON(bug_on_recovery);
1235
Oz Krakowskib992c682011-06-26 10:36:02 +03001236 /*
1237 * Advance security sequence number to overcome potential progress
1238 * in the firmware during recovery. This doens't hurt if the network is
1239 * not encrypted.
1240 */
1241 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1242 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1243 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1244
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001245 /* Prevent spurious TX during FW restart */
1246 ieee80211_stop_queues(wl->hw);
1247
Luciano Coelho33c2c062011-05-10 14:46:02 +03001248 if (wl->sched_scanning) {
1249 ieee80211_sched_scan_stopped(wl->hw);
1250 wl->sched_scanning = false;
1251 }
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001254 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001255
1256 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1257
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001258 ieee80211_restart_hw(wl->hw);
1259
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001260 /*
1261 * Its safe to enable TX now - the queues are stopped after a request
1262 * to restart the HW.
1263 */
1264 ieee80211_wake_queues(wl->hw);
1265
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001266out:
1267 mutex_unlock(&wl->mutex);
1268}
1269
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270static void wl1271_fw_wakeup(struct wl1271 *wl)
1271{
1272 u32 elp_reg;
1273
1274 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001275 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276}
1277
1278static int wl1271_setup(struct wl1271 *wl)
1279{
1280 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1281 if (!wl->fw_status)
1282 return -ENOMEM;
1283
1284 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1285 if (!wl->tx_res_if) {
1286 kfree(wl->fw_status);
1287 return -ENOMEM;
1288 }
1289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 return 0;
1291}
1292
1293static int wl1271_chip_wakeup(struct wl1271 *wl)
1294{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001295 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 int ret = 0;
1297
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001298 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001299 ret = wl1271_power_on(wl);
1300 if (ret < 0)
1301 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001303 wl1271_io_reset(wl);
1304 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305
1306 /* We don't need a real memory partition here, because we only want
1307 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001308 memset(&partition, 0, sizeof(partition));
1309 partition.reg.start = REGISTERS_BASE;
1310 partition.reg.size = REGISTERS_DOWN_SIZE;
1311 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312
1313 /* ELP module wake up */
1314 wl1271_fw_wakeup(wl);
1315
1316 /* whal_FwCtrl_BootSm() */
1317
1318 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001319 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
1321 /* 1. check if chip id is valid */
1322
1323 switch (wl->chip.id) {
1324 case CHIP_ID_1271_PG10:
1325 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1326 wl->chip.id);
1327
1328 ret = wl1271_setup(wl);
1329 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 break;
1332 case CHIP_ID_1271_PG20:
1333 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1334 wl->chip.id);
1335
Shahar Levi0c005042011-06-12 10:34:43 +03001336 /*
1337 * 'end-of-transaction flag' and 'LPD mode flag'
1338 * should be set in wl127x AP mode only
1339 */
Shahar Levi564f5952011-04-04 10:20:39 +03001340 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001341 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1342 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001343
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344 ret = wl1271_setup(wl);
1345 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001346 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001348 case CHIP_ID_1283_PG20:
1349 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1350 wl->chip.id);
1351
1352 ret = wl1271_setup(wl);
1353 if (ret < 0)
1354 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001355
Ido Yariv0da13da2011-03-31 10:06:58 +02001356 if (wl1271_set_block_size(wl))
1357 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001358 break;
1359 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001361 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 }
1365
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001366 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 ret = wl1271_fetch_firmware(wl);
1368 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 }
1371
1372 /* No NVS from netlink, try to get it from the filesystem */
1373 if (wl->nvs == NULL) {
1374 ret = wl1271_fetch_nvs(wl);
1375 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 }
1378
1379out:
1380 return ret;
1381}
1382
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383int wl1271_plt_start(struct wl1271 *wl)
1384{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001386 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001387 int ret;
1388
1389 mutex_lock(&wl->mutex);
1390
1391 wl1271_notice("power up");
1392
1393 if (wl->state != WL1271_STATE_OFF) {
1394 wl1271_error("cannot go into PLT state because not "
1395 "in off state: %d", wl->state);
1396 ret = -EBUSY;
1397 goto out;
1398 }
1399
Arik Nemtsov166d5042010-10-16 21:44:57 +02001400 wl->bss_type = BSS_TYPE_STA_BSS;
1401
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001402 while (retries) {
1403 retries--;
1404 ret = wl1271_chip_wakeup(wl);
1405 if (ret < 0)
1406 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 ret = wl1271_boot(wl);
1409 if (ret < 0)
1410 goto power_off;
1411
1412 ret = wl1271_plt_init(wl);
1413 if (ret < 0)
1414 goto irq_disable;
1415
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001416 wl->state = WL1271_STATE_PLT;
1417 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001418 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001419
Gery Kahn6f07b722011-07-18 14:21:49 +03001420 /* update hw/fw version info in wiphy struct */
1421 wiphy->hw_version = wl->chip.id;
1422 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1423 sizeof(wiphy->fw_version));
1424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 goto out;
1426
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001427irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001428 mutex_unlock(&wl->mutex);
1429 /* Unlocking the mutex in the middle of handling is
1430 inherently unsafe. In this case we deem it safe to do,
1431 because we need to let any possibly pending IRQ out of
1432 the system (and while we are WL1271_STATE_OFF the IRQ
1433 work function will not do anything.) Also, any other
1434 possible concurrent operations will fail due to the
1435 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001436 wl1271_disable_interrupts(wl);
1437 wl1271_flush_deferred_work(wl);
1438 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 mutex_lock(&wl->mutex);
1440power_off:
1441 wl1271_power_off(wl);
1442 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001444 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1445 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446out:
1447 mutex_unlock(&wl->mutex);
1448
1449 return ret;
1450}
1451
Luciano Coelho4623ec72011-03-21 19:26:41 +02001452static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453{
1454 int ret = 0;
1455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 wl1271_notice("power down");
1457
1458 if (wl->state != WL1271_STATE_PLT) {
1459 wl1271_error("cannot power down because not in PLT "
1460 "state: %d", wl->state);
1461 ret = -EBUSY;
1462 goto out;
1463 }
1464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 wl1271_power_off(wl);
1466
1467 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001468 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001471 wl1271_disable_interrupts(wl);
1472 wl1271_flush_deferred_work(wl);
1473 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001474 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475 mutex_lock(&wl->mutex);
1476out:
1477 return ret;
1478}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001479
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001480int wl1271_plt_stop(struct wl1271 *wl)
1481{
1482 int ret;
1483
1484 mutex_lock(&wl->mutex);
1485 ret = __wl1271_plt_stop(wl);
1486 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 return ret;
1488}
1489
Johannes Berg7bb45682011-02-24 14:42:06 +01001490static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491{
1492 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001494 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001495 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001497 mapping = skb_get_queue_mapping(skb);
1498 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
1500 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001501 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001502
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001503 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001504
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001505 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001506 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001507 if (!wl1271_is_active_sta(wl, hlid)) {
1508 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1509 hlid, q);
1510 dev_kfree_skb(skb);
1511 goto out;
1512 }
1513
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001514 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1515 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1516 } else {
1517 skb_queue_tail(&wl->tx_queue[q], skb);
1518 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001520 wl->tx_queue_count[q]++;
1521
1522 /*
1523 * The workqueue is slow to process the tx_queue and we need stop
1524 * the queue here, otherwise the queue will get too long.
1525 */
1526 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1527 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1528 ieee80211_stop_queue(wl->hw, mapping);
1529 set_bit(q, &wl->stopped_queues_map);
1530 }
1531
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 /*
1533 * The chip specific setup must run before the first TX packet -
1534 * before that, the tx_work will not be initialized!
1535 */
1536
Ido Yarivb07d4032011-03-01 15:14:43 +02001537 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1538 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001539 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001540
Arik Nemtsov04216da2011-08-14 13:17:38 +03001541out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001542 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543}
1544
Shahar Leviae47c452011-03-06 16:32:14 +02001545int wl1271_tx_dummy_packet(struct wl1271 *wl)
1546{
Ido Yariv990f5de2011-03-31 10:06:59 +02001547 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001548 int q;
1549
1550 /* no need to queue a new dummy packet if one is already pending */
1551 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1552 return 0;
1553
1554 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001555
Ido Yariv990f5de2011-03-31 10:06:59 +02001556 spin_lock_irqsave(&wl->wl_lock, flags);
1557 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001558 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 spin_unlock_irqrestore(&wl->wl_lock, flags);
1560
1561 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1562 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1563 wl1271_tx_work_locked(wl);
1564
1565 /*
1566 * If the FW TX is busy, TX work will be scheduled by the threaded
1567 * interrupt handler function
1568 */
1569 return 0;
1570}
1571
1572/*
1573 * The size of the dummy packet should be at least 1400 bytes. However, in
1574 * order to minimize the number of bus transactions, aligning it to 512 bytes
1575 * boundaries could be beneficial, performance wise
1576 */
1577#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1578
Luciano Coelhocf27d862011-04-01 21:08:23 +03001579static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001580{
1581 struct sk_buff *skb;
1582 struct ieee80211_hdr_3addr *hdr;
1583 unsigned int dummy_packet_size;
1584
1585 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1586 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1587
1588 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001589 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001590 wl1271_warning("Failed to allocate a dummy packet skb");
1591 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001592 }
1593
1594 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1595
1596 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1597 memset(hdr, 0, sizeof(*hdr));
1598 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001599 IEEE80211_STYPE_NULLFUNC |
1600 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001601
Ido Yariv990f5de2011-03-31 10:06:59 +02001602 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001603
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001604 /* Dummy packets require the TID to be management */
1605 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001606
1607 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001608 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001609 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001610
Ido Yariv990f5de2011-03-31 10:06:59 +02001611 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001612}
1613
Ido Yariv990f5de2011-03-31 10:06:59 +02001614
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001615static struct notifier_block wl1271_dev_notifier = {
1616 .notifier_call = wl1271_dev_notify,
1617};
1618
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001619#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001621{
Eliad Pellere85d1622011-06-27 13:06:43 +03001622 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001623
Eliad Peller94390642011-05-13 11:57:13 +03001624 mutex_lock(&wl->mutex);
1625
Eliad Pellere85d1622011-06-27 13:06:43 +03001626 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1627 goto out_unlock;
1628
Eliad Peller94390642011-05-13 11:57:13 +03001629 ret = wl1271_ps_elp_wakeup(wl);
1630 if (ret < 0)
1631 goto out_unlock;
1632
1633 /* enter psm if needed*/
1634 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1635 DECLARE_COMPLETION_ONSTACK(compl);
1636
1637 wl->ps_compl = &compl;
1638 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1639 wl->basic_rate, true);
1640 if (ret < 0)
1641 goto out_sleep;
1642
1643 /* we must unlock here so we will be able to get events */
1644 wl1271_ps_elp_sleep(wl);
1645 mutex_unlock(&wl->mutex);
1646
1647 ret = wait_for_completion_timeout(
1648 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1649 if (ret <= 0) {
1650 wl1271_warning("couldn't enter ps mode!");
1651 ret = -EBUSY;
1652 goto out;
1653 }
1654
1655 /* take mutex again, and wakeup */
1656 mutex_lock(&wl->mutex);
1657
1658 ret = wl1271_ps_elp_wakeup(wl);
1659 if (ret < 0)
1660 goto out_unlock;
1661 }
1662out_sleep:
1663 wl1271_ps_elp_sleep(wl);
1664out_unlock:
1665 mutex_unlock(&wl->mutex);
1666out:
1667 return ret;
1668
1669}
1670
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001671static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001672{
Eliad Pellere85d1622011-06-27 13:06:43 +03001673 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001674
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001675 mutex_lock(&wl->mutex);
1676
Eliad Pellere85d1622011-06-27 13:06:43 +03001677 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1678 goto out_unlock;
1679
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680 ret = wl1271_ps_elp_wakeup(wl);
1681 if (ret < 0)
1682 goto out_unlock;
1683
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001684 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001685
1686 wl1271_ps_elp_sleep(wl);
1687out_unlock:
1688 mutex_unlock(&wl->mutex);
1689 return ret;
1690
1691}
1692
1693static int wl1271_configure_suspend(struct wl1271 *wl)
1694{
1695 if (wl->bss_type == BSS_TYPE_STA_BSS)
1696 return wl1271_configure_suspend_sta(wl);
1697 if (wl->bss_type == BSS_TYPE_AP_BSS)
1698 return wl1271_configure_suspend_ap(wl);
1699 return 0;
1700}
1701
1702static void wl1271_configure_resume(struct wl1271 *wl)
1703{
1704 int ret;
1705 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1706 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1707
1708 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001709 return;
1710
1711 mutex_lock(&wl->mutex);
1712 ret = wl1271_ps_elp_wakeup(wl);
1713 if (ret < 0)
1714 goto out;
1715
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001716 if (is_sta) {
1717 /* exit psm if it wasn't configured */
1718 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1719 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1720 wl->basic_rate, true);
1721 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001722 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001723 }
Eliad Peller94390642011-05-13 11:57:13 +03001724
1725 wl1271_ps_elp_sleep(wl);
1726out:
1727 mutex_unlock(&wl->mutex);
1728}
1729
Eliad Peller402e48612011-05-13 11:57:09 +03001730static int wl1271_op_suspend(struct ieee80211_hw *hw,
1731 struct cfg80211_wowlan *wow)
1732{
1733 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 int ret;
1735
Eliad Peller402e48612011-05-13 11:57:09 +03001736 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001738
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 wl->wow_enabled = true;
1740 ret = wl1271_configure_suspend(wl);
1741 if (ret < 0) {
1742 wl1271_warning("couldn't prepare device to suspend");
1743 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001744 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 /* flush any remaining work */
1746 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001747
1748 /*
1749 * disable and re-enable interrupts in order to flush
1750 * the threaded_irq
1751 */
1752 wl1271_disable_interrupts(wl);
1753
1754 /*
1755 * set suspended flag to avoid triggering a new threaded_irq
1756 * work. no need for spinlock as interrupts are disabled.
1757 */
1758 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1759
1760 wl1271_enable_interrupts(wl);
1761 flush_work(&wl->tx_work);
1762 flush_delayed_work(&wl->pspoll_work);
1763 flush_delayed_work(&wl->elp_work);
1764
Eliad Peller402e48612011-05-13 11:57:09 +03001765 return 0;
1766}
1767
1768static int wl1271_op_resume(struct ieee80211_hw *hw)
1769{
1770 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 unsigned long flags;
1772 bool run_irq_work = false;
1773
Eliad Peller402e48612011-05-13 11:57:09 +03001774 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1775 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001776 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001777
1778 /*
1779 * re-enable irq_work enqueuing, and call irq_work directly if
1780 * there is a pending work.
1781 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001782 spin_lock_irqsave(&wl->wl_lock, flags);
1783 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1784 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1785 run_irq_work = true;
1786 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001787
Eliad Peller4a859df2011-06-06 12:21:52 +03001788 if (run_irq_work) {
1789 wl1271_debug(DEBUG_MAC80211,
1790 "run postponed irq_work directly");
1791 wl1271_irq(0, wl);
1792 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001793 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001794 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001795 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001796
Eliad Peller402e48612011-05-13 11:57:09 +03001797 return 0;
1798}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001799#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801static int wl1271_op_start(struct ieee80211_hw *hw)
1802{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001803 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1804
1805 /*
1806 * We have to delay the booting of the hardware because
1807 * we need to know the local MAC address before downloading and
1808 * initializing the firmware. The MAC address cannot be changed
1809 * after boot, and without the proper MAC address, the firmware
1810 * will not function properly.
1811 *
1812 * The MAC address is first known when the corresponding interface
1813 * is added. That is where we will initialize the hardware.
1814 */
1815
1816 return 0;
1817}
1818
1819static void wl1271_op_stop(struct ieee80211_hw *hw)
1820{
1821 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1822}
1823
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001824static u8 wl12xx_get_role_type(struct wl1271 *wl)
1825{
1826 switch (wl->bss_type) {
1827 case BSS_TYPE_AP_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001828 if (wl->p2p)
1829 return WL1271_ROLE_P2P_GO;
1830 else
1831 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001832
1833 case BSS_TYPE_STA_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001834 if (wl->p2p)
1835 return WL1271_ROLE_P2P_CL;
1836 else
1837 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001838
Eliad Peller227e81e2011-08-14 13:17:26 +03001839 case BSS_TYPE_IBSS:
1840 return WL1271_ROLE_IBSS;
1841
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001842 default:
1843 wl1271_error("invalid bss_type: %d", wl->bss_type);
1844 }
1845 return WL12XX_INVALID_ROLE_TYPE;
1846}
1847
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001848static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1849 struct ieee80211_vif *vif)
1850{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001852 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001853 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001855 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001856 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001858 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03001859 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860
1861 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001862 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001863 wl1271_debug(DEBUG_MAC80211,
1864 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001865 ret = -EBUSY;
1866 goto out;
1867 }
1868
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001869 /*
1870 * in some very corner case HW recovery scenarios its possible to
1871 * get here before __wl1271_op_remove_interface is complete, so
1872 * opt out if that is the case.
1873 */
1874 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1875 ret = -EBUSY;
1876 goto out;
1877 }
1878
Eliad Peller045c7452011-08-28 15:23:01 +03001879 switch (ieee80211_vif_type_p2p(vif)) {
1880 case NL80211_IFTYPE_P2P_CLIENT:
1881 wl->p2p = 1;
1882 /* fall-through */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001883 case NL80211_IFTYPE_STATION:
1884 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001885 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001886 break;
1887 case NL80211_IFTYPE_ADHOC:
1888 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001889 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001890 break;
Eliad Peller045c7452011-08-28 15:23:01 +03001891 case NL80211_IFTYPE_P2P_GO:
1892 wl->p2p = 1;
1893 /* fall-through */
Arik Nemtsov038d9252010-10-16 21:53:24 +02001894 case NL80211_IFTYPE_AP:
1895 wl->bss_type = BSS_TYPE_AP_BSS;
1896 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001897 default:
1898 ret = -EOPNOTSUPP;
1899 goto out;
1900 }
1901
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001902 role_type = wl12xx_get_role_type(wl);
1903 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1904 ret = -EINVAL;
1905 goto out;
1906 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001907 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908
1909 if (wl->state != WL1271_STATE_OFF) {
1910 wl1271_error("cannot start because not in off state: %d",
1911 wl->state);
1912 ret = -EBUSY;
1913 goto out;
1914 }
1915
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001916 while (retries) {
1917 retries--;
1918 ret = wl1271_chip_wakeup(wl);
1919 if (ret < 0)
1920 goto power_off;
1921
1922 ret = wl1271_boot(wl);
1923 if (ret < 0)
1924 goto power_off;
1925
Eliad Peller227e81e2011-08-14 13:17:26 +03001926 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1927 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001928 /*
1929 * The device role is a special role used for
1930 * rx and tx frames prior to association (as
1931 * the STA role can get packets only from
1932 * its associated bssid)
1933 */
1934 ret = wl12xx_cmd_role_enable(wl,
1935 WL1271_ROLE_DEVICE,
1936 &wl->dev_role_id);
1937 if (ret < 0)
1938 goto irq_disable;
1939 }
1940
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001941 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1942 if (ret < 0)
1943 goto irq_disable;
1944
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001945 ret = wl1271_hw_init(wl);
1946 if (ret < 0)
1947 goto irq_disable;
1948
Eliad Peller71125ab2010-10-28 21:46:43 +02001949 booted = true;
1950 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001952irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001953 mutex_unlock(&wl->mutex);
1954 /* Unlocking the mutex in the middle of handling is
1955 inherently unsafe. In this case we deem it safe to do,
1956 because we need to let any possibly pending IRQ out of
1957 the system (and while we are WL1271_STATE_OFF the IRQ
1958 work function will not do anything.) Also, any other
1959 possible concurrent operations will fail due to the
1960 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001961 wl1271_disable_interrupts(wl);
1962 wl1271_flush_deferred_work(wl);
1963 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001964 mutex_lock(&wl->mutex);
1965power_off:
1966 wl1271_power_off(wl);
1967 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968
Eliad Peller71125ab2010-10-28 21:46:43 +02001969 if (!booted) {
1970 wl1271_error("firmware boot failed despite %d retries",
1971 WL1271_BOOT_RETRIES);
1972 goto out;
1973 }
1974
1975 wl->vif = vif;
1976 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001977 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001978 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001979
1980 /* update hw/fw version info in wiphy struct */
1981 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001982 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001983 sizeof(wiphy->fw_version));
1984
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001985 /*
1986 * Now we know if 11a is supported (info from the NVS), so disable
1987 * 11a channels if not supported
1988 */
1989 if (!wl->enable_11a)
1990 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1991
1992 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1993 wl->enable_11a ? "" : "not ");
1994
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001995out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996 mutex_unlock(&wl->mutex);
1997
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001998 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001999 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002000 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002001 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 return ret;
2004}
2005
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002006static void __wl1271_op_remove_interface(struct wl1271 *wl,
2007 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002009 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002011 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002013 /* because of hardware recovery, we may get here twice */
2014 if (wl->state != WL1271_STATE_ON)
2015 return;
2016
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002017 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002019 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002020 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002021 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002022
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002023 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03002024 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002025 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002026
Luciano Coelho08688d62010-07-08 17:50:07 +03002027 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002028 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002029 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002030 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002031 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 }
2033
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002034 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2035 /* disable active roles */
2036 ret = wl1271_ps_elp_wakeup(wl);
2037 if (ret < 0)
2038 goto deinit;
2039
Eliad Peller04e80792011-08-14 13:17:09 +03002040 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2041 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2042 if (ret < 0)
2043 goto deinit;
2044 }
2045
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002046 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2047 if (ret < 0)
2048 goto deinit;
2049
2050 wl1271_ps_elp_sleep(wl);
2051 }
2052deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002053 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002054 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002055 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002056 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2057 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002058
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002059 /*
2060 * this must be before the cancel_work calls below, so that the work
2061 * functions don't perform further work.
2062 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 wl->state = WL1271_STATE_OFF;
2064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 mutex_unlock(&wl->mutex);
2066
Ido Yariva6208652011-03-01 15:14:41 +02002067 wl1271_disable_interrupts(wl);
2068 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002069 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002070 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002072 del_timer_sync(&wl->rx_streaming_timer);
2073 cancel_work_sync(&wl->rx_streaming_enable_work);
2074 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002075 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002076 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077
2078 mutex_lock(&wl->mutex);
2079
2080 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002081 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 wl1271_power_off(wl);
2083
2084 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002085 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002088 wl->set_bss_type = MAX_BSS_TYPE;
Eliad Peller045c7452011-08-28 15:23:01 +03002089 wl->p2p = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002090 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091
2092 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002093 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2095 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002096 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002097 wl->tx_results_count = 0;
2098 wl->tx_packets_count = 0;
2099 wl->time_offset = 0;
2100 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002101 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002102 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2103 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002104 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002105 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002106 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002107 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002108 wl->ap_fw_ps_map = 0;
2109 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002110 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002111 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002112 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002113 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2114 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002115 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002116 wl->active_sta_count = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002117
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002118 /* The system link is always allocated */
2119 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2120
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002121 /*
2122 * this is performed after the cancel_work calls and the associated
2123 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2124 * get executed before all these vars have been reset.
2125 */
2126 wl->flags = 0;
2127
Eliad Peller4d56ad92011-08-14 13:17:05 +03002128 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002129
Arik Nemtsov742246f2011-08-14 13:17:33 +03002130 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002131 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002132 wl->tx_allocated_pkts[i] = 0;
2133 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002134
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002136
2137 kfree(wl->fw_status);
2138 wl->fw_status = NULL;
2139 kfree(wl->tx_res_if);
2140 wl->tx_res_if = NULL;
2141 kfree(wl->target_mem_map);
2142 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002143}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002144
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002145static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2146 struct ieee80211_vif *vif)
2147{
2148 struct wl1271 *wl = hw->priv;
2149
2150 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002151 /*
2152 * wl->vif can be null here if someone shuts down the interface
2153 * just when hardware recovery has been started.
2154 */
2155 if (wl->vif) {
2156 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002157 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002158 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002159
Juuso Oikarinen67353292010-11-18 15:19:02 +02002160 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002161 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162}
2163
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002164static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002165{
2166 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002167 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002168
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002169 /*
2170 * One of the side effects of the JOIN command is that is clears
2171 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2172 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002173 * Currently the only valid scenario for JOIN during association
2174 * is on roaming, in which case we will also be given new keys.
2175 * Keep the below message for now, unless it starts bothering
2176 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002177 */
2178 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2179 wl1271_info("JOIN while associated.");
2180
2181 if (set_assoc)
2182 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2183
Eliad Peller227e81e2011-08-14 13:17:26 +03002184 if (is_ibss)
2185 ret = wl12xx_cmd_role_start_ibss(wl);
2186 else
2187 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002188 if (ret < 0)
2189 goto out;
2190
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002191 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2192 goto out;
2193
2194 /*
2195 * The join command disable the keep-alive mode, shut down its process,
2196 * and also clear the template config, so we need to reset it all after
2197 * the join. The acx_aid starts the keep-alive process, and the order
2198 * of the commands below is relevant.
2199 */
2200 ret = wl1271_acx_keep_alive_mode(wl, true);
2201 if (ret < 0)
2202 goto out;
2203
2204 ret = wl1271_acx_aid(wl, wl->aid);
2205 if (ret < 0)
2206 goto out;
2207
2208 ret = wl1271_cmd_build_klv_null_data(wl);
2209 if (ret < 0)
2210 goto out;
2211
2212 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2213 ACX_KEEP_ALIVE_TPL_VALID);
2214 if (ret < 0)
2215 goto out;
2216
2217out:
2218 return ret;
2219}
2220
2221static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002222{
2223 int ret;
2224
Shahar Levi6d158ff2011-09-08 13:01:33 +03002225 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2226 wl12xx_cmd_stop_channel_switch(wl);
2227 ieee80211_chswitch_done(wl->vif, false);
2228 }
2229
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002230 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002231 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002232 if (ret < 0)
2233 goto out;
2234
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002235 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002236
Oz Krakowskib992c682011-06-26 10:36:02 +03002237 /* reset TX security counters on a clean disconnect */
2238 wl->tx_security_last_seq_lsb = 0;
2239 wl->tx_security_seq = 0;
2240
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002241out:
2242 return ret;
2243}
2244
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002245static void wl1271_set_band_rate(struct wl1271 *wl)
2246{
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002247 wl->basic_rate_set = wl->bitrate_masks[wl->band];
2248 wl->rate_set = wl->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002249}
2250
Eliad Peller251c1772011-08-14 13:17:17 +03002251static bool wl12xx_is_roc(struct wl1271 *wl)
2252{
2253 u8 role_id;
2254
2255 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2256 if (role_id >= WL12XX_MAX_ROLES)
2257 return false;
2258
2259 return true;
2260}
2261
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002262static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002263{
2264 int ret;
2265
2266 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002267 /* no need to croc if we weren't busy (e.g. during boot) */
2268 if (wl12xx_is_roc(wl)) {
2269 ret = wl12xx_croc(wl, wl->dev_role_id);
2270 if (ret < 0)
2271 goto out;
2272
2273 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002274 if (ret < 0)
2275 goto out;
2276 }
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002277 wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002278 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002279 if (ret < 0)
2280 goto out;
2281 ret = wl1271_acx_keep_alive_config(
2282 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2283 ACX_KEEP_ALIVE_TPL_INVALID);
2284 if (ret < 0)
2285 goto out;
2286 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2287 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002288 /* The current firmware only supports sched_scan in idle */
2289 if (wl->sched_scanning) {
2290 wl1271_scan_sched_scan_stop(wl);
2291 ieee80211_sched_scan_stopped(wl->hw);
2292 }
2293
Eliad Peller251c1772011-08-14 13:17:17 +03002294 ret = wl12xx_cmd_role_start_dev(wl);
2295 if (ret < 0)
2296 goto out;
2297
2298 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002299 if (ret < 0)
2300 goto out;
2301 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2302 }
2303
2304out:
2305 return ret;
2306}
2307
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2309{
2310 struct wl1271 *wl = hw->priv;
2311 struct ieee80211_conf *conf = &hw->conf;
2312 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002313 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314
2315 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2316
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002317 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2318 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319 channel,
2320 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002321 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002322 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2323 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002325 /*
2326 * mac80211 will go to idle nearly immediately after transmitting some
2327 * frames, such as the deauth. To make sure those frames reach the air,
2328 * wait here until the TX queue is fully flushed.
2329 */
2330 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2331 (conf->flags & IEEE80211_CONF_IDLE))
2332 wl1271_tx_flush(wl);
2333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334 mutex_lock(&wl->mutex);
2335
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002336 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002337 /* we support configuring the channel and band while off */
2338 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2339 wl->band = conf->channel->band;
2340 wl->channel = channel;
2341 }
2342
Arik Nemtsov097f8822011-06-27 22:06:34 +03002343 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2344 wl->power_level = conf->power_level;
2345
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002346 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002347 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002348
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002349 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2350
Ido Yariva6208652011-03-01 15:14:41 +02002351 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 if (ret < 0)
2353 goto out;
2354
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002355 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002356 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2357 ((wl->band != conf->channel->band) ||
2358 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002359 /* send all pending packets */
2360 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002361 wl->band = conf->channel->band;
2362 wl->channel = channel;
2363
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002364 if (!is_ap) {
2365 /*
2366 * FIXME: the mac80211 should really provide a fixed
2367 * rate to use here. for now, just use the smallest
2368 * possible rate for the band as a fixed rate for
2369 * association frames and other control messages.
2370 */
2371 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2372 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002373
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002374 wl->basic_rate =
2375 wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002376 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002377 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002378 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002379 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002380
Eliad Peller251c1772011-08-14 13:17:17 +03002381 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2382 if (wl12xx_is_roc(wl)) {
2383 /* roaming */
2384 ret = wl12xx_croc(wl, wl->dev_role_id);
2385 if (ret < 0)
2386 goto out_sleep;
2387 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002388 ret = wl1271_join(wl, false);
2389 if (ret < 0)
2390 wl1271_warning("cmd join on channel "
2391 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002392 } else {
2393 /*
2394 * change the ROC channel. do it only if we are
2395 * not idle. otherwise, CROC will be called
2396 * anyway.
2397 */
2398 if (wl12xx_is_roc(wl) &&
2399 !(conf->flags & IEEE80211_CONF_IDLE)) {
2400 ret = wl12xx_croc(wl, wl->dev_role_id);
2401 if (ret < 0)
2402 goto out_sleep;
2403
2404 ret = wl12xx_roc(wl, wl->dev_role_id);
2405 if (ret < 0)
2406 wl1271_warning("roc failed %d",
2407 ret);
2408 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002409 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002410 }
2411 }
2412
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002413 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2414 ret = wl1271_sta_handle_idle(wl,
2415 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002416 if (ret < 0)
2417 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418 }
2419
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002420 /*
2421 * if mac80211 changes the PSM mode, make sure the mode is not
2422 * incorrectly changed after the pspoll failure active window.
2423 */
2424 if (changed & IEEE80211_CONF_CHANGE_PS)
2425 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2426
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002427 if (conf->flags & IEEE80211_CONF_PS &&
2428 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2429 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430
2431 /*
2432 * We enter PSM only if we're already associated.
2433 * If we're not, we'll enter it when joining an SSID,
2434 * through the bss_info_changed() hook.
2435 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002436 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002437 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002438 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002439 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002440 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002441 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002442 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002443 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002445 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002446
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002447 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002448 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002449 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450 }
2451
2452 if (conf->power_level != wl->power_level) {
2453 ret = wl1271_acx_tx_power(wl, conf->power_level);
2454 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002455 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456
2457 wl->power_level = conf->power_level;
2458 }
2459
2460out_sleep:
2461 wl1271_ps_elp_sleep(wl);
2462
2463out:
2464 mutex_unlock(&wl->mutex);
2465
2466 return ret;
2467}
2468
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002469struct wl1271_filter_params {
2470 bool enabled;
2471 int mc_list_length;
2472 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2473};
2474
Jiri Pirko22bedad2010-04-01 21:22:57 +00002475static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2476 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002477{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002478 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002479 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002480 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002481
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002482 if (unlikely(wl->state == WL1271_STATE_OFF))
2483 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002484
Juuso Oikarinen74441132009-10-13 12:47:53 +03002485 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002486 if (!fp) {
2487 wl1271_error("Out of memory setting filters.");
2488 return 0;
2489 }
2490
2491 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002492 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002493 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2494 fp->enabled = false;
2495 } else {
2496 fp->enabled = true;
2497 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002498 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002499 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002500 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002501 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002502 }
2503
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002504 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002505}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002507#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2508 FIF_ALLMULTI | \
2509 FIF_FCSFAIL | \
2510 FIF_BCN_PRBRESP_PROMISC | \
2511 FIF_CONTROL | \
2512 FIF_OTHER_BSS)
2513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002514static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2515 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002516 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002518 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002520 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521
Arik Nemtsov7d057862010-10-16 19:25:35 +02002522 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2523 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002525 mutex_lock(&wl->mutex);
2526
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002527 *total &= WL1271_SUPPORTED_FILTERS;
2528 changed &= WL1271_SUPPORTED_FILTERS;
2529
2530 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002531 goto out;
2532
Ido Yariva6208652011-03-01 15:14:41 +02002533 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002534 if (ret < 0)
2535 goto out;
2536
Arik Nemtsov7d057862010-10-16 19:25:35 +02002537 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2538 if (*total & FIF_ALLMULTI)
2539 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2540 else if (fp)
2541 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2542 fp->mc_list,
2543 fp->mc_list_length);
2544 if (ret < 0)
2545 goto out_sleep;
2546 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002547
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002548 /*
2549 * the fw doesn't provide an api to configure the filters. instead,
2550 * the filters configuration is based on the active roles / ROC
2551 * state.
2552 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002553
2554out_sleep:
2555 wl1271_ps_elp_sleep(wl);
2556
2557out:
2558 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002559 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560}
2561
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002562static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2563 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2564 u16 tx_seq_16)
2565{
2566 struct wl1271_ap_key *ap_key;
2567 int i;
2568
2569 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2570
2571 if (key_size > MAX_KEY_SIZE)
2572 return -EINVAL;
2573
2574 /*
2575 * Find next free entry in ap_keys. Also check we are not replacing
2576 * an existing key.
2577 */
2578 for (i = 0; i < MAX_NUM_KEYS; i++) {
2579 if (wl->recorded_ap_keys[i] == NULL)
2580 break;
2581
2582 if (wl->recorded_ap_keys[i]->id == id) {
2583 wl1271_warning("trying to record key replacement");
2584 return -EINVAL;
2585 }
2586 }
2587
2588 if (i == MAX_NUM_KEYS)
2589 return -EBUSY;
2590
2591 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2592 if (!ap_key)
2593 return -ENOMEM;
2594
2595 ap_key->id = id;
2596 ap_key->key_type = key_type;
2597 ap_key->key_size = key_size;
2598 memcpy(ap_key->key, key, key_size);
2599 ap_key->hlid = hlid;
2600 ap_key->tx_seq_32 = tx_seq_32;
2601 ap_key->tx_seq_16 = tx_seq_16;
2602
2603 wl->recorded_ap_keys[i] = ap_key;
2604 return 0;
2605}
2606
2607static void wl1271_free_ap_keys(struct wl1271 *wl)
2608{
2609 int i;
2610
2611 for (i = 0; i < MAX_NUM_KEYS; i++) {
2612 kfree(wl->recorded_ap_keys[i]);
2613 wl->recorded_ap_keys[i] = NULL;
2614 }
2615}
2616
2617static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2618{
2619 int i, ret = 0;
2620 struct wl1271_ap_key *key;
2621 bool wep_key_added = false;
2622
2623 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002624 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002625 if (wl->recorded_ap_keys[i] == NULL)
2626 break;
2627
2628 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002629 hlid = key->hlid;
2630 if (hlid == WL12XX_INVALID_LINK_ID)
2631 hlid = wl->ap_bcast_hlid;
2632
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002633 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2634 key->id, key->key_type,
2635 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002636 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002637 key->tx_seq_16);
2638 if (ret < 0)
2639 goto out;
2640
2641 if (key->key_type == KEY_WEP)
2642 wep_key_added = true;
2643 }
2644
2645 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002646 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002647 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002648 if (ret < 0)
2649 goto out;
2650 }
2651
2652out:
2653 wl1271_free_ap_keys(wl);
2654 return ret;
2655}
2656
2657static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2658 u8 key_size, const u8 *key, u32 tx_seq_32,
2659 u16 tx_seq_16, struct ieee80211_sta *sta)
2660{
2661 int ret;
2662 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2663
2664 if (is_ap) {
2665 struct wl1271_station *wl_sta;
2666 u8 hlid;
2667
2668 if (sta) {
2669 wl_sta = (struct wl1271_station *)sta->drv_priv;
2670 hlid = wl_sta->hlid;
2671 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002672 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002673 }
2674
2675 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2676 /*
2677 * We do not support removing keys after AP shutdown.
2678 * Pretend we do to make mac80211 happy.
2679 */
2680 if (action != KEY_ADD_OR_REPLACE)
2681 return 0;
2682
2683 ret = wl1271_record_ap_key(wl, id,
2684 key_type, key_size,
2685 key, hlid, tx_seq_32,
2686 tx_seq_16);
2687 } else {
2688 ret = wl1271_cmd_set_ap_key(wl, action,
2689 id, key_type, key_size,
2690 key, hlid, tx_seq_32,
2691 tx_seq_16);
2692 }
2693
2694 if (ret < 0)
2695 return ret;
2696 } else {
2697 const u8 *addr;
2698 static const u8 bcast_addr[ETH_ALEN] = {
2699 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2700 };
2701
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002702 /*
2703 * A STA set to GEM cipher requires 2 tx spare blocks.
2704 * Return to default value when GEM cipher key is removed
2705 */
2706 if (key_type == KEY_GEM) {
2707 if (action == KEY_ADD_OR_REPLACE)
2708 wl->tx_spare_blocks = 2;
2709 else if (action == KEY_REMOVE)
2710 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2711 }
2712
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002713 addr = sta ? sta->addr : bcast_addr;
2714
2715 if (is_zero_ether_addr(addr)) {
2716 /* We dont support TX only encryption */
2717 return -EOPNOTSUPP;
2718 }
2719
2720 /* The wl1271 does not allow to remove unicast keys - they
2721 will be cleared automatically on next CMD_JOIN. Ignore the
2722 request silently, as we dont want the mac80211 to emit
2723 an error message. */
2724 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2725 return 0;
2726
Eliad Peller010d3d32011-08-14 13:17:31 +03002727 /* don't remove key if hlid was already deleted */
2728 if (action == KEY_REMOVE &&
2729 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2730 return 0;
2731
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002732 ret = wl1271_cmd_set_sta_key(wl, action,
2733 id, key_type, key_size,
2734 key, addr, tx_seq_32,
2735 tx_seq_16);
2736 if (ret < 0)
2737 return ret;
2738
2739 /* the default WEP key needs to be configured at least once */
2740 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002741 ret = wl12xx_cmd_set_default_wep_key(wl,
2742 wl->default_key,
2743 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002744 if (ret < 0)
2745 return ret;
2746 }
2747 }
2748
2749 return 0;
2750}
2751
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2753 struct ieee80211_vif *vif,
2754 struct ieee80211_sta *sta,
2755 struct ieee80211_key_conf *key_conf)
2756{
2757 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002759 u32 tx_seq_32 = 0;
2760 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761 u8 key_type;
2762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002763 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2764
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002765 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002767 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002768 key_conf->keylen, key_conf->flags);
2769 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2770
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002771 mutex_lock(&wl->mutex);
2772
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002773 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2774 ret = -EAGAIN;
2775 goto out_unlock;
2776 }
2777
Ido Yariva6208652011-03-01 15:14:41 +02002778 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002779 if (ret < 0)
2780 goto out_unlock;
2781
Johannes Berg97359d12010-08-10 09:46:38 +02002782 switch (key_conf->cipher) {
2783 case WLAN_CIPHER_SUITE_WEP40:
2784 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785 key_type = KEY_WEP;
2786
2787 key_conf->hw_key_idx = key_conf->keyidx;
2788 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002789 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 key_type = KEY_TKIP;
2791
2792 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002793 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2794 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002795 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002796 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797 key_type = KEY_AES;
2798
2799 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002800 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2801 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002803 case WL1271_CIPHER_SUITE_GEM:
2804 key_type = KEY_GEM;
2805 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2806 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2807 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002809 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002810
2811 ret = -EOPNOTSUPP;
2812 goto out_sleep;
2813 }
2814
2815 switch (cmd) {
2816 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002817 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2818 key_conf->keyidx, key_type,
2819 key_conf->keylen, key_conf->key,
2820 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 if (ret < 0) {
2822 wl1271_error("Could not add or replace key");
2823 goto out_sleep;
2824 }
2825 break;
2826
2827 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002828 ret = wl1271_set_key(wl, KEY_REMOVE,
2829 key_conf->keyidx, key_type,
2830 key_conf->keylen, key_conf->key,
2831 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832 if (ret < 0) {
2833 wl1271_error("Could not remove key");
2834 goto out_sleep;
2835 }
2836 break;
2837
2838 default:
2839 wl1271_error("Unsupported key cmd 0x%x", cmd);
2840 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841 break;
2842 }
2843
2844out_sleep:
2845 wl1271_ps_elp_sleep(wl);
2846
2847out_unlock:
2848 mutex_unlock(&wl->mutex);
2849
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002850 return ret;
2851}
2852
2853static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002854 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855 struct cfg80211_scan_request *req)
2856{
2857 struct wl1271 *wl = hw->priv;
2858 int ret;
2859 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002860 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002861
2862 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2863
2864 if (req->n_ssids) {
2865 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002866 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002867 }
2868
2869 mutex_lock(&wl->mutex);
2870
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002871 if (wl->state == WL1271_STATE_OFF) {
2872 /*
2873 * We cannot return -EBUSY here because cfg80211 will expect
2874 * a call to ieee80211_scan_completed if we do - in this case
2875 * there won't be any call.
2876 */
2877 ret = -EAGAIN;
2878 goto out;
2879 }
2880
Ido Yariva6208652011-03-01 15:14:41 +02002881 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002882 if (ret < 0)
2883 goto out;
2884
Eliad Peller251c1772011-08-14 13:17:17 +03002885 /* cancel ROC before scanning */
2886 if (wl12xx_is_roc(wl)) {
2887 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2888 /* don't allow scanning right now */
2889 ret = -EBUSY;
2890 goto out_sleep;
2891 }
2892 wl12xx_croc(wl, wl->dev_role_id);
2893 wl12xx_cmd_role_stop_dev(wl);
2894 }
2895
Luciano Coelho5924f892010-08-04 03:46:22 +03002896 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002897out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899out:
2900 mutex_unlock(&wl->mutex);
2901
2902 return ret;
2903}
2904
Eliad Peller73ecce32011-06-27 13:06:45 +03002905static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2906 struct ieee80211_vif *vif)
2907{
2908 struct wl1271 *wl = hw->priv;
2909 int ret;
2910
2911 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2912
2913 mutex_lock(&wl->mutex);
2914
2915 if (wl->state == WL1271_STATE_OFF)
2916 goto out;
2917
2918 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2919 goto out;
2920
2921 ret = wl1271_ps_elp_wakeup(wl);
2922 if (ret < 0)
2923 goto out;
2924
2925 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2926 ret = wl1271_scan_stop(wl);
2927 if (ret < 0)
2928 goto out_sleep;
2929 }
2930 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2931 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2932 wl->scan.req = NULL;
2933 ieee80211_scan_completed(wl->hw, true);
2934
2935out_sleep:
2936 wl1271_ps_elp_sleep(wl);
2937out:
2938 mutex_unlock(&wl->mutex);
2939
2940 cancel_delayed_work_sync(&wl->scan_complete_work);
2941}
2942
Luciano Coelho33c2c062011-05-10 14:46:02 +03002943static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2944 struct ieee80211_vif *vif,
2945 struct cfg80211_sched_scan_request *req,
2946 struct ieee80211_sched_scan_ies *ies)
2947{
2948 struct wl1271 *wl = hw->priv;
2949 int ret;
2950
2951 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2952
2953 mutex_lock(&wl->mutex);
2954
2955 ret = wl1271_ps_elp_wakeup(wl);
2956 if (ret < 0)
2957 goto out;
2958
2959 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2960 if (ret < 0)
2961 goto out_sleep;
2962
2963 ret = wl1271_scan_sched_scan_start(wl);
2964 if (ret < 0)
2965 goto out_sleep;
2966
2967 wl->sched_scanning = true;
2968
2969out_sleep:
2970 wl1271_ps_elp_sleep(wl);
2971out:
2972 mutex_unlock(&wl->mutex);
2973 return ret;
2974}
2975
2976static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2977 struct ieee80211_vif *vif)
2978{
2979 struct wl1271 *wl = hw->priv;
2980 int ret;
2981
2982 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2983
2984 mutex_lock(&wl->mutex);
2985
2986 ret = wl1271_ps_elp_wakeup(wl);
2987 if (ret < 0)
2988 goto out;
2989
2990 wl1271_scan_sched_scan_stop(wl);
2991
2992 wl1271_ps_elp_sleep(wl);
2993out:
2994 mutex_unlock(&wl->mutex);
2995}
2996
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002997static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2998{
2999 struct wl1271 *wl = hw->priv;
3000 int ret = 0;
3001
3002 mutex_lock(&wl->mutex);
3003
3004 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3005 ret = -EAGAIN;
3006 goto out;
3007 }
3008
Ido Yariva6208652011-03-01 15:14:41 +02003009 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003010 if (ret < 0)
3011 goto out;
3012
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003013 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003014 if (ret < 0)
3015 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3016
3017 wl1271_ps_elp_sleep(wl);
3018
3019out:
3020 mutex_unlock(&wl->mutex);
3021
3022 return ret;
3023}
3024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3026{
3027 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003028 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029
3030 mutex_lock(&wl->mutex);
3031
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003032 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3033 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003034 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003035 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003036
Ido Yariva6208652011-03-01 15:14:41 +02003037 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 if (ret < 0)
3039 goto out;
3040
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003041 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003042 if (ret < 0)
3043 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3044
3045 wl1271_ps_elp_sleep(wl);
3046
3047out:
3048 mutex_unlock(&wl->mutex);
3049
3050 return ret;
3051}
3052
Arik Nemtsove78a2872010-10-16 19:07:21 +02003053static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003054 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003055{
Eliad Peller889cb362011-05-01 09:56:45 +03003056 u8 ssid_len;
3057 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3058 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003059
Eliad Peller889cb362011-05-01 09:56:45 +03003060 if (!ptr) {
3061 wl1271_error("No SSID in IEs!");
3062 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003063 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003064
Eliad Peller889cb362011-05-01 09:56:45 +03003065 ssid_len = ptr[1];
3066 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3067 wl1271_error("SSID is too long!");
3068 return -EINVAL;
3069 }
3070
3071 wl->ssid_len = ssid_len;
3072 memcpy(wl->ssid, ptr+2, ssid_len);
3073 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003074}
3075
Eliad Pellerd48055d2011-09-15 12:07:04 +03003076static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3077{
3078 int len;
3079 const u8 *next, *end = skb->data + skb->len;
3080 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3081 skb->len - ieoffset);
3082 if (!ie)
3083 return;
3084 len = ie[1] + 2;
3085 next = ie + len;
3086 memmove(ie, next, end - next);
3087 skb_trim(skb, skb->len - len);
3088}
3089
Eliad Peller26b4bf22011-09-15 12:07:05 +03003090static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3091 unsigned int oui, u8 oui_type,
3092 int ieoffset)
3093{
3094 int len;
3095 const u8 *next, *end = skb->data + skb->len;
3096 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3097 skb->data + ieoffset,
3098 skb->len - ieoffset);
3099 if (!ie)
3100 return;
3101 len = ie[1] + 2;
3102 next = ie + len;
3103 memmove(ie, next, end - next);
3104 skb_trim(skb, skb->len - len);
3105}
3106
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003107static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
3108 u8 *probe_rsp_data,
3109 size_t probe_rsp_len,
3110 u32 rates)
3111{
3112 struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
3113 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3114 int ssid_ie_offset, ie_offset, templ_len;
3115 const u8 *ptr;
3116
3117 /* no need to change probe response if the SSID is set correctly */
3118 if (wl->ssid_len > 0)
3119 return wl1271_cmd_template_set(wl,
3120 CMD_TEMPL_AP_PROBE_RESPONSE,
3121 probe_rsp_data,
3122 probe_rsp_len, 0,
3123 rates);
3124
3125 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3126 wl1271_error("probe_rsp template too big");
3127 return -EINVAL;
3128 }
3129
3130 /* start searching from IE offset */
3131 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3132
3133 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3134 probe_rsp_len - ie_offset);
3135 if (!ptr) {
3136 wl1271_error("No SSID in beacon!");
3137 return -EINVAL;
3138 }
3139
3140 ssid_ie_offset = ptr - probe_rsp_data;
3141 ptr += (ptr[1] + 2);
3142
3143 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3144
3145 /* insert SSID from bss_conf */
3146 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3147 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3148 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3149 bss_conf->ssid, bss_conf->ssid_len);
3150 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3151
3152 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3153 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3154 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3155
3156 return wl1271_cmd_template_set(wl,
3157 CMD_TEMPL_AP_PROBE_RESPONSE,
3158 probe_rsp_templ,
3159 templ_len, 0,
3160 rates);
3161}
3162
Arik Nemtsove78a2872010-10-16 19:07:21 +02003163static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3164 struct ieee80211_bss_conf *bss_conf,
3165 u32 changed)
3166{
3167 int ret = 0;
3168
3169 if (changed & BSS_CHANGED_ERP_SLOT) {
3170 if (bss_conf->use_short_slot)
3171 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3172 else
3173 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3174 if (ret < 0) {
3175 wl1271_warning("Set slot time failed %d", ret);
3176 goto out;
3177 }
3178 }
3179
3180 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3181 if (bss_conf->use_short_preamble)
3182 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3183 else
3184 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3185 }
3186
3187 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3188 if (bss_conf->use_cts_prot)
3189 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3190 else
3191 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3192 if (ret < 0) {
3193 wl1271_warning("Set ctsprotect failed %d", ret);
3194 goto out;
3195 }
3196 }
3197
3198out:
3199 return ret;
3200}
3201
3202static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3203 struct ieee80211_vif *vif,
3204 struct ieee80211_bss_conf *bss_conf,
3205 u32 changed)
3206{
3207 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3208 int ret = 0;
3209
3210 if ((changed & BSS_CHANGED_BEACON_INT)) {
3211 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3212 bss_conf->beacon_int);
3213
3214 wl->beacon_int = bss_conf->beacon_int;
3215 }
3216
3217 if ((changed & BSS_CHANGED_BEACON)) {
3218 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003219 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003220 int ieoffset = offsetof(struct ieee80211_mgmt,
3221 u.beacon.variable);
3222 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3223 u16 tmpl_id;
3224
3225 if (!beacon)
3226 goto out;
3227
3228 wl1271_debug(DEBUG_MASTER, "beacon updated");
3229
3230 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3231 if (ret < 0) {
3232 dev_kfree_skb(beacon);
3233 goto out;
3234 }
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003235 min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003236 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3237 CMD_TEMPL_BEACON;
3238 ret = wl1271_cmd_template_set(wl, tmpl_id,
3239 beacon->data,
3240 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003241 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003242 if (ret < 0) {
3243 dev_kfree_skb(beacon);
3244 goto out;
3245 }
3246
Eliad Pellerd48055d2011-09-15 12:07:04 +03003247 /* remove TIM ie from probe response */
3248 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3249
Eliad Peller26b4bf22011-09-15 12:07:05 +03003250 /*
3251 * remove p2p ie from probe response.
3252 * the fw reponds to probe requests that don't include
3253 * the p2p ie. probe requests with p2p ie will be passed,
3254 * and will be responded by the supplicant (the spec
3255 * forbids including the p2p ie when responding to probe
3256 * requests that didn't include it).
3257 */
3258 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3259 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3260
Arik Nemtsove78a2872010-10-16 19:07:21 +02003261 hdr = (struct ieee80211_hdr *) beacon->data;
3262 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3263 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003264 if (is_ap)
3265 ret = wl1271_ap_set_probe_resp_tmpl(wl,
3266 beacon->data,
3267 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003268 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003269 else
3270 ret = wl1271_cmd_template_set(wl,
3271 CMD_TEMPL_PROBE_RESPONSE,
3272 beacon->data,
3273 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003274 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003275 dev_kfree_skb(beacon);
3276 if (ret < 0)
3277 goto out;
3278 }
3279
3280out:
3281 return ret;
3282}
3283
3284/* AP mode changes */
3285static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003286 struct ieee80211_vif *vif,
3287 struct ieee80211_bss_conf *bss_conf,
3288 u32 changed)
3289{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003290 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003291
Arik Nemtsove78a2872010-10-16 19:07:21 +02003292 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3293 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003295 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
3296 wl->band);
3297 wl->basic_rate = wl1271_tx_min_rate_get(wl,
3298 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003299
Arik Nemtsov70f47422011-04-18 14:15:25 +03003300 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003301 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003302 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003303 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003304 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003305
3306 ret = wl1271_ap_init_templates(wl);
3307 if (ret < 0)
3308 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003309 }
3310
Arik Nemtsove78a2872010-10-16 19:07:21 +02003311 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3312 if (ret < 0)
3313 goto out;
3314
3315 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3316 if (bss_conf->enable_beacon) {
3317 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003318 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003319 if (ret < 0)
3320 goto out;
3321
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003322 ret = wl1271_ap_init_hwenc(wl);
3323 if (ret < 0)
3324 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003325
3326 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3327 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003328 }
3329 } else {
3330 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003331 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003332 if (ret < 0)
3333 goto out;
3334
3335 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3336 wl1271_debug(DEBUG_AP, "stopped AP");
3337 }
3338 }
3339 }
3340
3341 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3342 if (ret < 0)
3343 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003344
3345 /* Handle HT information change */
3346 if ((changed & BSS_CHANGED_HT) &&
3347 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3348 ret = wl1271_acx_set_ht_information(wl,
3349 bss_conf->ht_operation_mode);
3350 if (ret < 0) {
3351 wl1271_warning("Set ht information failed %d", ret);
3352 goto out;
3353 }
3354 }
3355
Arik Nemtsove78a2872010-10-16 19:07:21 +02003356out:
3357 return;
3358}
3359
3360/* STA/IBSS mode changes */
3361static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3362 struct ieee80211_vif *vif,
3363 struct ieee80211_bss_conf *bss_conf,
3364 u32 changed)
3365{
3366 bool do_join = false, set_assoc = false;
3367 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003368 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003369 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003371 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003372 bool sta_exists = false;
3373 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374
3375 if (is_ibss) {
3376 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3377 changed);
3378 if (ret < 0)
3379 goto out;
3380 }
3381
Eliad Peller227e81e2011-08-14 13:17:26 +03003382 if (changed & BSS_CHANGED_IBSS) {
3383 if (bss_conf->ibss_joined) {
3384 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3385 ibss_joined = true;
3386 } else {
3387 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3388 &wl->flags)) {
3389 wl1271_unjoin(wl);
3390 wl12xx_cmd_role_start_dev(wl);
3391 wl12xx_roc(wl, wl->dev_role_id);
3392 }
3393 }
3394 }
3395
3396 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 do_join = true;
3398
3399 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003400 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 do_join = true;
3402
Eliad Peller227e81e2011-08-14 13:17:26 +03003403 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003404 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3405 bss_conf->enable_beacon ? "enabled" : "disabled");
3406
3407 if (bss_conf->enable_beacon)
3408 wl->set_bss_type = BSS_TYPE_IBSS;
3409 else
3410 wl->set_bss_type = BSS_TYPE_STA_BSS;
3411 do_join = true;
3412 }
3413
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003415 bool enable = false;
3416 if (bss_conf->cqm_rssi_thold)
3417 enable = true;
3418 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3419 bss_conf->cqm_rssi_thold,
3420 bss_conf->cqm_rssi_hyst);
3421 if (ret < 0)
3422 goto out;
3423 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3424 }
3425
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003426 if ((changed & BSS_CHANGED_BSSID) &&
3427 /*
3428 * Now we know the correct bssid, so we send a new join command
3429 * and enable the BSSID filter
3430 */
3431 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003433
Eliad Pellerfa287b82010-12-26 09:27:50 +01003434 if (!is_zero_ether_addr(wl->bssid)) {
3435 ret = wl1271_cmd_build_null_data(wl);
3436 if (ret < 0)
3437 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003438
Eliad Pellerfa287b82010-12-26 09:27:50 +01003439 ret = wl1271_build_qos_null_data(wl);
3440 if (ret < 0)
3441 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003442
Eliad Pellerfa287b82010-12-26 09:27:50 +01003443 /* Need to update the BSSID (for filtering etc) */
3444 do_join = true;
3445 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003446 }
3447
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003448 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3449 rcu_read_lock();
3450 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3451 if (!sta)
3452 goto sta_not_found;
3453
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003454 /* save the supp_rates of the ap */
3455 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3456 if (sta->ht_cap.ht_supported)
3457 sta_rate_set |=
3458 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003459 sta_ht_cap = sta->ht_cap;
3460 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003461
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003462sta_not_found:
3463 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003464 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003465
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003467 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003468 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003469 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003470 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003471 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003472
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003473 wl->ps_poll_failures = 0;
3474
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003475 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003476 * use basic rates from AP, and determine lowest rate
3477 * to use with control frames.
3478 */
3479 rates = bss_conf->basic_rates;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003480 wl->basic_rate_set =
3481 wl1271_tx_enabled_rates_get(wl, rates,
3482 wl->band);
3483 wl->basic_rate =
3484 wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003485 if (sta_rate_set)
3486 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003487 sta_rate_set,
3488 wl->band);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003489 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003490 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003491 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003492
3493 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003494 * with wl1271, we don't need to update the
3495 * beacon_int and dtim_period, because the firmware
3496 * updates it by itself when the first beacon is
3497 * received after a join.
3498 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3500 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003501 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003502
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003503 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003504 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003505 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003506 dev_kfree_skb(wl->probereq);
3507 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3508 ieoffset = offsetof(struct ieee80211_mgmt,
3509 u.probe_req.variable);
3510 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003511
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003512 /* enable the connection monitoring feature */
3513 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003516 } else {
3517 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003518 bool was_assoc =
3519 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3520 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003521 bool was_ifup =
3522 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3523 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003524 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003525
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003526 /* free probe-request template */
3527 dev_kfree_skb(wl->probereq);
3528 wl->probereq = NULL;
3529
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003530 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003531 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003532
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003533 /* revert back to minimum rates for the current band */
3534 wl1271_set_band_rate(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003535 wl->basic_rate =
3536 wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003537 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003538 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003540
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003541 /* disable connection monitor features */
3542 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003543
3544 /* Disable the keep-alive feature */
3545 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003546 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003548
3549 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003550 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003551 u32 conf_flags = wl->hw->conf.flags;
3552 /*
3553 * we might have to disable roc, if there was
3554 * no IF_OPER_UP notification.
3555 */
3556 if (!was_ifup) {
3557 ret = wl12xx_croc(wl, wl->role_id);
3558 if (ret < 0)
3559 goto out;
3560 }
3561 /*
3562 * (we also need to disable roc in case of
3563 * roaming on the same channel. until we will
3564 * have a better flow...)
3565 */
3566 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3567 ret = wl12xx_croc(wl, wl->dev_role_id);
3568 if (ret < 0)
3569 goto out;
3570 }
3571
Eliad Peller30df14d2011-04-05 19:13:28 +03003572 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003573 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3574 wl12xx_cmd_role_start_dev(wl);
3575 wl12xx_roc(wl, wl->dev_role_id);
3576 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003577 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578 }
3579 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003580
Eliad Pellerd192d262011-05-24 14:33:08 +03003581 if (changed & BSS_CHANGED_IBSS) {
3582 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3583 bss_conf->ibss_joined);
3584
3585 if (bss_conf->ibss_joined) {
3586 u32 rates = bss_conf->basic_rates;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003587 wl->basic_rate_set =
3588 wl1271_tx_enabled_rates_get(wl, rates,
3589 wl->band);
3590 wl->basic_rate =
3591 wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003592
Shahar Levi06b660e2011-09-05 13:54:36 +03003593 /* by default, use 11b + OFDM rates */
Eliad Pellerd192d262011-05-24 14:33:08 +03003594 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3595 ret = wl1271_acx_sta_rate_policies(wl);
3596 if (ret < 0)
3597 goto out;
3598 }
3599 }
3600
Arik Nemtsove78a2872010-10-16 19:07:21 +02003601 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3602 if (ret < 0)
3603 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003604
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003605 if (changed & BSS_CHANGED_ARP_FILTER) {
3606 __be32 addr = bss_conf->arp_addr_list[0];
3607 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3608
Eliad Pellerc5312772010-12-09 11:31:27 +02003609 if (bss_conf->arp_addr_cnt == 1 &&
3610 bss_conf->arp_filter_enabled) {
3611 /*
3612 * The template should have been configured only upon
3613 * association. however, it seems that the correct ip
3614 * isn't being set (when sending), so we have to
3615 * reconfigure the template upon every ip change.
3616 */
3617 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3618 if (ret < 0) {
3619 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003620 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003621 }
3622
3623 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003624 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003625 addr);
3626 } else
3627 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003628
3629 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003630 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003631 }
3632
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003633 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003634 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003635 if (ret < 0) {
3636 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003637 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003638 }
Eliad Peller251c1772011-08-14 13:17:17 +03003639
3640 /* ROC until connected (after EAPOL exchange) */
3641 if (!is_ibss) {
3642 ret = wl12xx_roc(wl, wl->role_id);
3643 if (ret < 0)
3644 goto out;
3645
3646 wl1271_check_operstate(wl,
3647 ieee80211_get_operstate(vif));
3648 }
3649 /*
3650 * stop device role if started (we might already be in
3651 * STA role). TODO: make it better.
3652 */
3653 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3654 ret = wl12xx_croc(wl, wl->dev_role_id);
3655 if (ret < 0)
3656 goto out;
3657
3658 ret = wl12xx_cmd_role_stop_dev(wl);
3659 if (ret < 0)
3660 goto out;
3661 }
Eliad Peller05dba352011-08-23 16:37:01 +03003662
3663 /* If we want to go in PSM but we're not there yet */
3664 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3665 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3666 enum wl1271_cmd_ps_mode mode;
3667
3668 mode = STATION_POWER_SAVE_MODE;
3669 ret = wl1271_ps_set_mode(wl, mode,
3670 wl->basic_rate,
3671 true);
3672 if (ret < 0)
3673 goto out;
3674 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003675 }
3676
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003677 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003678 if (sta_exists) {
3679 if ((changed & BSS_CHANGED_HT) &&
3680 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003681 ret = wl1271_acx_set_ht_capabilities(wl,
3682 &sta_ht_cap,
3683 true,
3684 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003685 if (ret < 0) {
3686 wl1271_warning("Set ht cap true failed %d",
3687 ret);
3688 goto out;
3689 }
3690 }
3691 /* handle new association without HT and disassociation */
3692 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003693 ret = wl1271_acx_set_ht_capabilities(wl,
3694 &sta_ht_cap,
3695 false,
3696 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003697 if (ret < 0) {
3698 wl1271_warning("Set ht cap false failed %d",
3699 ret);
3700 goto out;
3701 }
3702 }
3703 }
3704
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003705 /* Handle HT information change. Done after join. */
3706 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003707 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3708 ret = wl1271_acx_set_ht_information(wl,
3709 bss_conf->ht_operation_mode);
3710 if (ret < 0) {
3711 wl1271_warning("Set ht information failed %d", ret);
3712 goto out;
3713 }
3714 }
3715
Arik Nemtsove78a2872010-10-16 19:07:21 +02003716out:
3717 return;
3718}
3719
3720static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3721 struct ieee80211_vif *vif,
3722 struct ieee80211_bss_conf *bss_conf,
3723 u32 changed)
3724{
3725 struct wl1271 *wl = hw->priv;
3726 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3727 int ret;
3728
3729 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3730 (int)changed);
3731
3732 mutex_lock(&wl->mutex);
3733
3734 if (unlikely(wl->state == WL1271_STATE_OFF))
3735 goto out;
3736
Ido Yariva6208652011-03-01 15:14:41 +02003737 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003738 if (ret < 0)
3739 goto out;
3740
3741 if (is_ap)
3742 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3743 else
3744 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3745
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003746 wl1271_ps_elp_sleep(wl);
3747
3748out:
3749 mutex_unlock(&wl->mutex);
3750}
3751
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003752static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3753 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003754 const struct ieee80211_tx_queue_params *params)
3755{
3756 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003757 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003758 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003759
3760 mutex_lock(&wl->mutex);
3761
3762 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3763
Kalle Valo4695dc92010-03-18 12:26:38 +02003764 if (params->uapsd)
3765 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3766 else
3767 ps_scheme = CONF_PS_SCHEME_LEGACY;
3768
Arik Nemtsov488fc542010-10-16 20:33:45 +02003769 if (wl->state == WL1271_STATE_OFF) {
3770 /*
3771 * If the state is off, the parameters will be recorded and
3772 * configured on init. This happens in AP-mode.
3773 */
3774 struct conf_tx_ac_category *conf_ac =
3775 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3776 struct conf_tx_tid *conf_tid =
3777 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3778
3779 conf_ac->ac = wl1271_tx_get_queue(queue);
3780 conf_ac->cw_min = (u8)params->cw_min;
3781 conf_ac->cw_max = params->cw_max;
3782 conf_ac->aifsn = params->aifs;
3783 conf_ac->tx_op_limit = params->txop << 5;
3784
3785 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3786 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3787 conf_tid->tsid = wl1271_tx_get_queue(queue);
3788 conf_tid->ps_scheme = ps_scheme;
3789 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3790 conf_tid->apsd_conf[0] = 0;
3791 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003792 goto out;
3793 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003794
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003795 ret = wl1271_ps_elp_wakeup(wl);
3796 if (ret < 0)
3797 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003798
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003799 /*
3800 * the txop is confed in units of 32us by the mac80211,
3801 * we need us
3802 */
3803 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3804 params->cw_min, params->cw_max,
3805 params->aifs, params->txop << 5);
3806 if (ret < 0)
3807 goto out_sleep;
3808
3809 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3810 CONF_CHANNEL_TYPE_EDCF,
3811 wl1271_tx_get_queue(queue),
3812 ps_scheme, CONF_ACK_POLICY_LEGACY,
3813 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003814
3815out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003816 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003817
3818out:
3819 mutex_unlock(&wl->mutex);
3820
3821 return ret;
3822}
3823
Eliad Peller37a41b42011-09-21 14:06:11 +03003824static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3825 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003826{
3827
3828 struct wl1271 *wl = hw->priv;
3829 u64 mactime = ULLONG_MAX;
3830 int ret;
3831
3832 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3833
3834 mutex_lock(&wl->mutex);
3835
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003836 if (unlikely(wl->state == WL1271_STATE_OFF))
3837 goto out;
3838
Ido Yariva6208652011-03-01 15:14:41 +02003839 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003840 if (ret < 0)
3841 goto out;
3842
3843 ret = wl1271_acx_tsf_info(wl, &mactime);
3844 if (ret < 0)
3845 goto out_sleep;
3846
3847out_sleep:
3848 wl1271_ps_elp_sleep(wl);
3849
3850out:
3851 mutex_unlock(&wl->mutex);
3852 return mactime;
3853}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003854
John W. Linvilleece550d2010-07-28 16:41:06 -04003855static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3856 struct survey_info *survey)
3857{
3858 struct wl1271 *wl = hw->priv;
3859 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003860
John W. Linvilleece550d2010-07-28 16:41:06 -04003861 if (idx != 0)
3862 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003863
John W. Linvilleece550d2010-07-28 16:41:06 -04003864 survey->channel = conf->channel;
3865 survey->filled = SURVEY_INFO_NOISE_DBM;
3866 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003867
John W. Linvilleece550d2010-07-28 16:41:06 -04003868 return 0;
3869}
3870
Arik Nemtsov409622e2011-02-23 00:22:29 +02003871static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003872 struct ieee80211_sta *sta,
3873 u8 *hlid)
3874{
3875 struct wl1271_station *wl_sta;
3876 int id;
3877
3878 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3879 if (id >= AP_MAX_STATIONS) {
3880 wl1271_warning("could not allocate HLID - too much stations");
3881 return -EBUSY;
3882 }
3883
3884 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003885 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003886 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3887 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003888 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003889 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003890 return 0;
3891}
3892
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003893void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003894{
3895 int id = hlid - WL1271_AP_STA_HLID_START;
3896
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003897 if (hlid < WL1271_AP_STA_HLID_START)
3898 return;
3899
3900 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003901 return;
3902
Arik Nemtsov04216da2011-08-14 13:17:38 +03003903 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003904 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003905 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003906 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003907 __clear_bit(hlid, &wl->ap_ps_map);
3908 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003909 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003910}
3911
3912static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3913 struct ieee80211_vif *vif,
3914 struct ieee80211_sta *sta)
3915{
3916 struct wl1271 *wl = hw->priv;
3917 int ret = 0;
3918 u8 hlid;
3919
3920 mutex_lock(&wl->mutex);
3921
3922 if (unlikely(wl->state == WL1271_STATE_OFF))
3923 goto out;
3924
3925 if (wl->bss_type != BSS_TYPE_AP_BSS)
3926 goto out;
3927
3928 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3929
Arik Nemtsov409622e2011-02-23 00:22:29 +02003930 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003931 if (ret < 0)
3932 goto out;
3933
Ido Yariva6208652011-03-01 15:14:41 +02003934 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003935 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003936 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003937
Eliad Pellerc690ec82011-08-14 13:17:07 +03003938 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003939 if (ret < 0)
3940 goto out_sleep;
3941
Eliad Pellerb67476e2011-08-14 13:17:23 +03003942 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3943 if (ret < 0)
3944 goto out_sleep;
3945
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003946 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3947 if (ret < 0)
3948 goto out_sleep;
3949
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003950out_sleep:
3951 wl1271_ps_elp_sleep(wl);
3952
Arik Nemtsov409622e2011-02-23 00:22:29 +02003953out_free_sta:
3954 if (ret < 0)
3955 wl1271_free_sta(wl, hlid);
3956
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003957out:
3958 mutex_unlock(&wl->mutex);
3959 return ret;
3960}
3961
3962static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3963 struct ieee80211_vif *vif,
3964 struct ieee80211_sta *sta)
3965{
3966 struct wl1271 *wl = hw->priv;
3967 struct wl1271_station *wl_sta;
3968 int ret = 0, id;
3969
3970 mutex_lock(&wl->mutex);
3971
3972 if (unlikely(wl->state == WL1271_STATE_OFF))
3973 goto out;
3974
3975 if (wl->bss_type != BSS_TYPE_AP_BSS)
3976 goto out;
3977
3978 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3979
3980 wl_sta = (struct wl1271_station *)sta->drv_priv;
3981 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3982 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3983 goto out;
3984
Ido Yariva6208652011-03-01 15:14:41 +02003985 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003986 if (ret < 0)
3987 goto out;
3988
Eliad Pellerc690ec82011-08-14 13:17:07 +03003989 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003990 if (ret < 0)
3991 goto out_sleep;
3992
Arik Nemtsov409622e2011-02-23 00:22:29 +02003993 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003994
3995out_sleep:
3996 wl1271_ps_elp_sleep(wl);
3997
3998out:
3999 mutex_unlock(&wl->mutex);
4000 return ret;
4001}
4002
Luciano Coelho4623ec72011-03-21 19:26:41 +02004003static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4004 struct ieee80211_vif *vif,
4005 enum ieee80211_ampdu_mlme_action action,
4006 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4007 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004008{
4009 struct wl1271 *wl = hw->priv;
4010 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004011 u8 hlid, *ba_bitmap;
4012
4013 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4014 tid);
4015
4016 /* sanity check - the fields in FW are only 8bits wide */
4017 if (WARN_ON(tid > 0xFF))
4018 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004019
4020 mutex_lock(&wl->mutex);
4021
4022 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4023 ret = -EAGAIN;
4024 goto out;
4025 }
4026
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004027 if (wl->bss_type == BSS_TYPE_STA_BSS) {
4028 hlid = wl->sta_hlid;
4029 ba_bitmap = &wl->ba_rx_bitmap;
4030 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
4031 struct wl1271_station *wl_sta;
4032
4033 wl_sta = (struct wl1271_station *)sta->drv_priv;
4034 hlid = wl_sta->hlid;
4035 ba_bitmap = &wl->links[hlid].ba_bitmap;
4036 } else {
4037 ret = -EINVAL;
4038 goto out;
4039 }
4040
Ido Yariva6208652011-03-01 15:14:41 +02004041 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004042 if (ret < 0)
4043 goto out;
4044
Shahar Levi70559a02011-05-22 16:10:22 +03004045 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4046 tid, action);
4047
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004048 switch (action) {
4049 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004050 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004051 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004052 break;
4053 }
4054
4055 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4056 ret = -EBUSY;
4057 wl1271_error("exceeded max RX BA sessions");
4058 break;
4059 }
4060
4061 if (*ba_bitmap & BIT(tid)) {
4062 ret = -EINVAL;
4063 wl1271_error("cannot enable RX BA session on active "
4064 "tid: %d", tid);
4065 break;
4066 }
4067
4068 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4069 hlid);
4070 if (!ret) {
4071 *ba_bitmap |= BIT(tid);
4072 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004073 }
4074 break;
4075
4076 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004077 if (!(*ba_bitmap & BIT(tid))) {
4078 ret = -EINVAL;
4079 wl1271_error("no active RX BA session on tid: %d",
4080 tid);
4081 break;
4082 }
4083
4084 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4085 hlid);
4086 if (!ret) {
4087 *ba_bitmap &= ~BIT(tid);
4088 wl->ba_rx_session_count--;
4089 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004090 break;
4091
4092 /*
4093 * The BA initiator session management in FW independently.
4094 * Falling break here on purpose for all TX APDU commands.
4095 */
4096 case IEEE80211_AMPDU_TX_START:
4097 case IEEE80211_AMPDU_TX_STOP:
4098 case IEEE80211_AMPDU_TX_OPERATIONAL:
4099 ret = -EINVAL;
4100 break;
4101
4102 default:
4103 wl1271_error("Incorrect ampdu action id=%x\n", action);
4104 ret = -EINVAL;
4105 }
4106
4107 wl1271_ps_elp_sleep(wl);
4108
4109out:
4110 mutex_unlock(&wl->mutex);
4111
4112 return ret;
4113}
4114
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004115static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4116 struct ieee80211_vif *vif,
4117 const struct cfg80211_bitrate_mask *mask)
4118{
4119 struct wl1271 *wl = hw->priv;
4120 int i;
4121
4122 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4123 mask->control[NL80211_BAND_2GHZ].legacy,
4124 mask->control[NL80211_BAND_5GHZ].legacy);
4125
4126 mutex_lock(&wl->mutex);
4127
4128 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4129 wl->bitrate_masks[i] =
4130 wl1271_tx_enabled_rates_get(wl,
4131 mask->control[i].legacy,
4132 i);
4133 mutex_unlock(&wl->mutex);
4134
4135 return 0;
4136}
4137
Shahar Levi6d158ff2011-09-08 13:01:33 +03004138static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4139 struct ieee80211_channel_switch *ch_switch)
4140{
4141 struct wl1271 *wl = hw->priv;
4142 int ret;
4143
4144 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4145
4146 mutex_lock(&wl->mutex);
4147
4148 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4149 mutex_unlock(&wl->mutex);
4150 ieee80211_chswitch_done(wl->vif, false);
4151 return;
4152 }
4153
4154 ret = wl1271_ps_elp_wakeup(wl);
4155 if (ret < 0)
4156 goto out;
4157
4158 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4159
4160 if (!ret)
4161 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4162
4163 wl1271_ps_elp_sleep(wl);
4164
4165out:
4166 mutex_unlock(&wl->mutex);
4167}
4168
Arik Nemtsov33437892011-04-26 23:35:39 +03004169static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4170{
4171 struct wl1271 *wl = hw->priv;
4172 bool ret = false;
4173
4174 mutex_lock(&wl->mutex);
4175
4176 if (unlikely(wl->state == WL1271_STATE_OFF))
4177 goto out;
4178
4179 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004180 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004181
4182 /* the above is appropriate for STA mode for PS purposes */
4183 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
4184
4185out:
4186 mutex_unlock(&wl->mutex);
4187
4188 return ret;
4189}
4190
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004191/* can't be const, mac80211 writes to this */
4192static struct ieee80211_rate wl1271_rates[] = {
4193 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004194 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4195 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004196 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004197 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4198 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004199 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4200 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004201 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4202 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004203 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4204 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004205 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4206 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004207 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4208 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004209 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4210 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004211 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004212 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4213 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004214 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004215 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4216 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004217 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004218 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4219 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004220 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004221 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4222 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004223 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004224 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4225 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004226 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004227 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4228 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004229 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004230 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4231 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004232};
4233
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004234/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004235static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004236 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004237 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004238 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4239 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4240 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004241 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004242 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4243 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4244 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004245 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004246 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4247 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4248 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004249 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004250};
4251
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004252/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004253static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004254 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004255 7, /* CONF_HW_RXTX_RATE_MCS7 */
4256 6, /* CONF_HW_RXTX_RATE_MCS6 */
4257 5, /* CONF_HW_RXTX_RATE_MCS5 */
4258 4, /* CONF_HW_RXTX_RATE_MCS4 */
4259 3, /* CONF_HW_RXTX_RATE_MCS3 */
4260 2, /* CONF_HW_RXTX_RATE_MCS2 */
4261 1, /* CONF_HW_RXTX_RATE_MCS1 */
4262 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004263
4264 11, /* CONF_HW_RXTX_RATE_54 */
4265 10, /* CONF_HW_RXTX_RATE_48 */
4266 9, /* CONF_HW_RXTX_RATE_36 */
4267 8, /* CONF_HW_RXTX_RATE_24 */
4268
4269 /* TI-specific rate */
4270 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4271
4272 7, /* CONF_HW_RXTX_RATE_18 */
4273 6, /* CONF_HW_RXTX_RATE_12 */
4274 3, /* CONF_HW_RXTX_RATE_11 */
4275 5, /* CONF_HW_RXTX_RATE_9 */
4276 4, /* CONF_HW_RXTX_RATE_6 */
4277 2, /* CONF_HW_RXTX_RATE_5_5 */
4278 1, /* CONF_HW_RXTX_RATE_2 */
4279 0 /* CONF_HW_RXTX_RATE_1 */
4280};
4281
Shahar Levie8b03a22010-10-13 16:09:39 +02004282/* 11n STA capabilities */
4283#define HW_RX_HIGHEST_RATE 72
4284
Shahar Levi00d20102010-11-08 11:20:10 +00004285#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004286 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4287 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004288 .ht_supported = true, \
4289 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4290 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4291 .mcs = { \
4292 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4293 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4294 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4295 }, \
4296}
4297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004298/* can't be const, mac80211 writes to this */
4299static struct ieee80211_supported_band wl1271_band_2ghz = {
4300 .channels = wl1271_channels,
4301 .n_channels = ARRAY_SIZE(wl1271_channels),
4302 .bitrates = wl1271_rates,
4303 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004304 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004305};
4306
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004307/* 5 GHz data rates for WL1273 */
4308static struct ieee80211_rate wl1271_rates_5ghz[] = {
4309 { .bitrate = 60,
4310 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4311 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4312 { .bitrate = 90,
4313 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4314 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4315 { .bitrate = 120,
4316 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4317 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4318 { .bitrate = 180,
4319 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4320 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4321 { .bitrate = 240,
4322 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4323 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4324 { .bitrate = 360,
4325 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4326 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4327 { .bitrate = 480,
4328 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4329 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4330 { .bitrate = 540,
4331 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4332 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4333};
4334
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004335/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004336static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004337 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4338 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4339 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4340 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4341 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4342 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4343 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4344 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4345 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4346 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4347 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4348 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4349 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4350 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4351 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4352 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4353 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4354 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4355 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4356 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4357 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4358 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4359 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4360 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4361 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4362 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4363 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4364 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4365 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4366 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4367 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4368 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4369 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4370 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004371};
4372
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004373/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004374static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004375 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004376 7, /* CONF_HW_RXTX_RATE_MCS7 */
4377 6, /* CONF_HW_RXTX_RATE_MCS6 */
4378 5, /* CONF_HW_RXTX_RATE_MCS5 */
4379 4, /* CONF_HW_RXTX_RATE_MCS4 */
4380 3, /* CONF_HW_RXTX_RATE_MCS3 */
4381 2, /* CONF_HW_RXTX_RATE_MCS2 */
4382 1, /* CONF_HW_RXTX_RATE_MCS1 */
4383 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004384
4385 7, /* CONF_HW_RXTX_RATE_54 */
4386 6, /* CONF_HW_RXTX_RATE_48 */
4387 5, /* CONF_HW_RXTX_RATE_36 */
4388 4, /* CONF_HW_RXTX_RATE_24 */
4389
4390 /* TI-specific rate */
4391 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4392
4393 3, /* CONF_HW_RXTX_RATE_18 */
4394 2, /* CONF_HW_RXTX_RATE_12 */
4395 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4396 1, /* CONF_HW_RXTX_RATE_9 */
4397 0, /* CONF_HW_RXTX_RATE_6 */
4398 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4399 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4400 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4401};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004402
4403static struct ieee80211_supported_band wl1271_band_5ghz = {
4404 .channels = wl1271_channels_5ghz,
4405 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4406 .bitrates = wl1271_rates_5ghz,
4407 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004408 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004409};
4410
Tobias Klausera0ea9492010-05-20 10:38:11 +02004411static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004412 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4413 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4414};
4415
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416static const struct ieee80211_ops wl1271_ops = {
4417 .start = wl1271_op_start,
4418 .stop = wl1271_op_stop,
4419 .add_interface = wl1271_op_add_interface,
4420 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004421#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004422 .suspend = wl1271_op_suspend,
4423 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004424#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004425 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004426 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427 .configure_filter = wl1271_op_configure_filter,
4428 .tx = wl1271_op_tx,
4429 .set_key = wl1271_op_set_key,
4430 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004431 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004432 .sched_scan_start = wl1271_op_sched_scan_start,
4433 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004435 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004436 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004437 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004438 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004439 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004440 .sta_add = wl1271_op_sta_add,
4441 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004442 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004443 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004444 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004445 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004446 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447};
4448
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004449
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004450u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004451{
4452 u8 idx;
4453
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004454 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004455
4456 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4457 wl1271_error("Illegal RX rate from HW: %d", rate);
4458 return 0;
4459 }
4460
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004461 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004462 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4463 wl1271_error("Unsupported RX rate from HW: %d", rate);
4464 return 0;
4465 }
4466
4467 return idx;
4468}
4469
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004470static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4471 struct device_attribute *attr,
4472 char *buf)
4473{
4474 struct wl1271 *wl = dev_get_drvdata(dev);
4475 ssize_t len;
4476
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004477 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004478
4479 mutex_lock(&wl->mutex);
4480 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4481 wl->sg_enabled);
4482 mutex_unlock(&wl->mutex);
4483
4484 return len;
4485
4486}
4487
4488static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4489 struct device_attribute *attr,
4490 const char *buf, size_t count)
4491{
4492 struct wl1271 *wl = dev_get_drvdata(dev);
4493 unsigned long res;
4494 int ret;
4495
Luciano Coelho6277ed62011-04-01 17:49:54 +03004496 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004497 if (ret < 0) {
4498 wl1271_warning("incorrect value written to bt_coex_mode");
4499 return count;
4500 }
4501
4502 mutex_lock(&wl->mutex);
4503
4504 res = !!res;
4505
4506 if (res == wl->sg_enabled)
4507 goto out;
4508
4509 wl->sg_enabled = res;
4510
4511 if (wl->state == WL1271_STATE_OFF)
4512 goto out;
4513
Ido Yariva6208652011-03-01 15:14:41 +02004514 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004515 if (ret < 0)
4516 goto out;
4517
4518 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4519 wl1271_ps_elp_sleep(wl);
4520
4521 out:
4522 mutex_unlock(&wl->mutex);
4523 return count;
4524}
4525
4526static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4527 wl1271_sysfs_show_bt_coex_state,
4528 wl1271_sysfs_store_bt_coex_state);
4529
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004530static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4531 struct device_attribute *attr,
4532 char *buf)
4533{
4534 struct wl1271 *wl = dev_get_drvdata(dev);
4535 ssize_t len;
4536
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004537 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004538
4539 mutex_lock(&wl->mutex);
4540 if (wl->hw_pg_ver >= 0)
4541 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4542 else
4543 len = snprintf(buf, len, "n/a\n");
4544 mutex_unlock(&wl->mutex);
4545
4546 return len;
4547}
4548
Gery Kahn6f07b722011-07-18 14:21:49 +03004549static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004550 wl1271_sysfs_show_hw_pg_ver, NULL);
4551
Ido Yariv95dac04f2011-06-06 14:57:06 +03004552static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4553 struct bin_attribute *bin_attr,
4554 char *buffer, loff_t pos, size_t count)
4555{
4556 struct device *dev = container_of(kobj, struct device, kobj);
4557 struct wl1271 *wl = dev_get_drvdata(dev);
4558 ssize_t len;
4559 int ret;
4560
4561 ret = mutex_lock_interruptible(&wl->mutex);
4562 if (ret < 0)
4563 return -ERESTARTSYS;
4564
4565 /* Let only one thread read the log at a time, blocking others */
4566 while (wl->fwlog_size == 0) {
4567 DEFINE_WAIT(wait);
4568
4569 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4570 &wait,
4571 TASK_INTERRUPTIBLE);
4572
4573 if (wl->fwlog_size != 0) {
4574 finish_wait(&wl->fwlog_waitq, &wait);
4575 break;
4576 }
4577
4578 mutex_unlock(&wl->mutex);
4579
4580 schedule();
4581 finish_wait(&wl->fwlog_waitq, &wait);
4582
4583 if (signal_pending(current))
4584 return -ERESTARTSYS;
4585
4586 ret = mutex_lock_interruptible(&wl->mutex);
4587 if (ret < 0)
4588 return -ERESTARTSYS;
4589 }
4590
4591 /* Check if the fwlog is still valid */
4592 if (wl->fwlog_size < 0) {
4593 mutex_unlock(&wl->mutex);
4594 return 0;
4595 }
4596
4597 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4598 len = min(count, (size_t)wl->fwlog_size);
4599 wl->fwlog_size -= len;
4600 memcpy(buffer, wl->fwlog, len);
4601
4602 /* Make room for new messages */
4603 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4604
4605 mutex_unlock(&wl->mutex);
4606
4607 return len;
4608}
4609
4610static struct bin_attribute fwlog_attr = {
4611 .attr = {.name = "fwlog", .mode = S_IRUSR},
4612 .read = wl1271_sysfs_read_fwlog,
4613};
4614
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004615int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004616{
4617 int ret;
4618
4619 if (wl->mac80211_registered)
4620 return 0;
4621
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004622 ret = wl1271_fetch_nvs(wl);
4623 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004624 /* NOTE: The wl->nvs->nvs element must be first, in
4625 * order to simplify the casting, we assume it is at
4626 * the beginning of the wl->nvs structure.
4627 */
4628 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004629
4630 wl->mac_addr[0] = nvs_ptr[11];
4631 wl->mac_addr[1] = nvs_ptr[10];
4632 wl->mac_addr[2] = nvs_ptr[6];
4633 wl->mac_addr[3] = nvs_ptr[5];
4634 wl->mac_addr[4] = nvs_ptr[4];
4635 wl->mac_addr[5] = nvs_ptr[3];
4636 }
4637
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004638 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4639
4640 ret = ieee80211_register_hw(wl->hw);
4641 if (ret < 0) {
4642 wl1271_error("unable to register mac80211 hw: %d", ret);
4643 return ret;
4644 }
4645
4646 wl->mac80211_registered = true;
4647
Eliad Pellerd60080a2010-11-24 12:53:16 +02004648 wl1271_debugfs_init(wl);
4649
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004650 register_netdevice_notifier(&wl1271_dev_notifier);
4651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652 wl1271_notice("loaded");
4653
4654 return 0;
4655}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004656EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004657
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004658void wl1271_unregister_hw(struct wl1271 *wl)
4659{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004660 if (wl->state == WL1271_STATE_PLT)
4661 __wl1271_plt_stop(wl);
4662
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004663 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004664 ieee80211_unregister_hw(wl->hw);
4665 wl->mac80211_registered = false;
4666
4667}
4668EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4669
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004670int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004671{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004672 static const u32 cipher_suites[] = {
4673 WLAN_CIPHER_SUITE_WEP40,
4674 WLAN_CIPHER_SUITE_WEP104,
4675 WLAN_CIPHER_SUITE_TKIP,
4676 WLAN_CIPHER_SUITE_CCMP,
4677 WL1271_CIPHER_SUITE_GEM,
4678 };
4679
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004680 /* The tx descriptor buffer and the TKIP space. */
4681 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4682 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004683
4684 /* unit us */
4685 /* FIXME: find a proper value */
4686 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004687 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004688
4689 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004690 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004691 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004692 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004693 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004694 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004695 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004696 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004697 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004698 IEEE80211_HW_AP_LINK_PS |
4699 IEEE80211_HW_AMPDU_AGGREGATION |
4700 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004701
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004702 wl->hw->wiphy->cipher_suites = cipher_suites;
4703 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4704
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004705 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004706 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4707 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004708 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004709 wl->hw->wiphy->max_sched_scan_ssids = 16;
4710 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004711 /*
4712 * Maximum length of elements in scanning probe request templates
4713 * should be the maximum length possible for a template, without
4714 * the IEEE80211 header of the template
4715 */
Eliad Peller154037d2011-08-14 13:17:12 +03004716 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004717 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004718
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004719 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4720 sizeof(struct ieee80211_header);
4721
Eliad Peller1ec23f72011-08-25 14:26:54 +03004722 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4723
Luciano Coelho4a31c112011-03-21 23:16:14 +02004724 /* make sure all our channels fit in the scanned_ch bitmask */
4725 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4726 ARRAY_SIZE(wl1271_channels_5ghz) >
4727 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004728 /*
4729 * We keep local copies of the band structs because we need to
4730 * modify them on a per-device basis.
4731 */
4732 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4733 sizeof(wl1271_band_2ghz));
4734 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4735 sizeof(wl1271_band_5ghz));
4736
4737 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4738 &wl->bands[IEEE80211_BAND_2GHZ];
4739 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4740 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004741
Kalle Valo12bd8942010-03-18 12:26:33 +02004742 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004743 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004744
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004745 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4746
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004747 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004748
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004749 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4750
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004751 wl->hw->max_rx_aggregation_subframes = 8;
4752
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004753 return 0;
4754}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004755EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004756
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004757#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004758
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004759struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004760{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004761 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004762 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004763 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004764 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004765 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004766
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004767 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4768
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004769 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4770 if (!hw) {
4771 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004772 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004773 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004774 }
4775
Julia Lawall929ebd32010-05-15 23:16:39 +02004776 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004777 if (!plat_dev) {
4778 wl1271_error("could not allocate platform_device");
4779 ret = -ENOMEM;
4780 goto err_plat_alloc;
4781 }
4782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004783 wl = hw->priv;
4784 memset(wl, 0, sizeof(*wl));
4785
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004786 INIT_LIST_HEAD(&wl->list);
4787
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004788 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004789 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004790
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004791 for (i = 0; i < NUM_TX_QUEUES; i++)
4792 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004793
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004794 for (i = 0; i < NUM_TX_QUEUES; i++)
4795 for (j = 0; j < AP_MAX_LINKS; j++)
4796 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4797
Ido Yariva6208652011-03-01 15:14:41 +02004798 skb_queue_head_init(&wl->deferred_rx_queue);
4799 skb_queue_head_init(&wl->deferred_tx_queue);
4800
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004801 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004802 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004803 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004804 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4805 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4806 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004807 INIT_WORK(&wl->rx_streaming_enable_work,
4808 wl1271_rx_streaming_enable_work);
4809 INIT_WORK(&wl->rx_streaming_disable_work,
4810 wl1271_rx_streaming_disable_work);
4811
Eliad Peller92ef8962011-06-07 12:50:46 +03004812 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4813 if (!wl->freezable_wq) {
4814 ret = -ENOMEM;
4815 goto err_hw;
4816 }
4817
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004818 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004819 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004820 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004821 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004822 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004823 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004824 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004825 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004826 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004827 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004828 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004829 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004830 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004831 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004832 wl->bss_type = MAX_BSS_TYPE;
4833 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004834 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004835 wl->ap_ps_map = 0;
4836 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004837 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004838 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004839 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004840 wl->tx_security_seq = 0;
4841 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004842 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004843 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004844 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004845 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004846 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4847 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004848 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004849 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4850 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004851 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004852 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4853 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004854 wl->fwlog_size = 0;
4855 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004856
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004857 /* The system link is always allocated */
4858 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4859
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004860 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004861 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004862 wl->tx_frames[i] = NULL;
4863
4864 spin_lock_init(&wl->wl_lock);
4865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004866 wl->state = WL1271_STATE_OFF;
4867 mutex_init(&wl->mutex);
4868
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004869 /* Apply default driver configuration. */
4870 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004871 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4872 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004873
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004874 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4875 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4876 if (!wl->aggr_buf) {
4877 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004878 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004879 }
4880
Ido Yariv990f5de2011-03-31 10:06:59 +02004881 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4882 if (!wl->dummy_packet) {
4883 ret = -ENOMEM;
4884 goto err_aggr;
4885 }
4886
Ido Yariv95dac04f2011-06-06 14:57:06 +03004887 /* Allocate one page for the FW log */
4888 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4889 if (!wl->fwlog) {
4890 ret = -ENOMEM;
4891 goto err_dummy_packet;
4892 }
4893
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004894 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004895 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004896 if (ret) {
4897 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004898 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004899 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004900 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004901
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004902 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004903 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004904 if (ret < 0) {
4905 wl1271_error("failed to create sysfs file bt_coex_state");
4906 goto err_platform;
4907 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004908
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004909 /* Create sysfs file to get HW PG version */
4910 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4911 if (ret < 0) {
4912 wl1271_error("failed to create sysfs file hw_pg_ver");
4913 goto err_bt_coex_state;
4914 }
4915
Ido Yariv95dac04f2011-06-06 14:57:06 +03004916 /* Create sysfs file for the FW log */
4917 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4918 if (ret < 0) {
4919 wl1271_error("failed to create sysfs file fwlog");
4920 goto err_hw_pg_ver;
4921 }
4922
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004923 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004924
Ido Yariv95dac04f2011-06-06 14:57:06 +03004925err_hw_pg_ver:
4926 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4927
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004928err_bt_coex_state:
4929 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4930
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004931err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004932 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004933
Ido Yariv95dac04f2011-06-06 14:57:06 +03004934err_fwlog:
4935 free_page((unsigned long)wl->fwlog);
4936
Ido Yariv990f5de2011-03-31 10:06:59 +02004937err_dummy_packet:
4938 dev_kfree_skb(wl->dummy_packet);
4939
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004940err_aggr:
4941 free_pages((unsigned long)wl->aggr_buf, order);
4942
Eliad Peller92ef8962011-06-07 12:50:46 +03004943err_wq:
4944 destroy_workqueue(wl->freezable_wq);
4945
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004946err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004947 wl1271_debugfs_exit(wl);
4948 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004949
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004950err_plat_alloc:
4951 ieee80211_free_hw(hw);
4952
4953err_hw_alloc:
4954
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004955 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004956}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004957EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004958
4959int wl1271_free_hw(struct wl1271 *wl)
4960{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004961 /* Unblock any fwlog readers */
4962 mutex_lock(&wl->mutex);
4963 wl->fwlog_size = -1;
4964 wake_up_interruptible_all(&wl->fwlog_waitq);
4965 mutex_unlock(&wl->mutex);
4966
4967 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004968
4969 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4970
4971 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004972 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004973 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004974 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004975 free_pages((unsigned long)wl->aggr_buf,
4976 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004977 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004978
4979 wl1271_debugfs_exit(wl);
4980
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004981 vfree(wl->fw);
4982 wl->fw = NULL;
4983 kfree(wl->nvs);
4984 wl->nvs = NULL;
4985
4986 kfree(wl->fw_status);
4987 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004988 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004989
4990 ieee80211_free_hw(wl->hw);
4991
4992 return 0;
4993}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004994EXPORT_SYMBOL_GPL(wl1271_free_hw);
4995
Guy Eilam491bbd62011-01-12 10:33:29 +01004996u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004997EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004998module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004999MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5000
Ido Yariv95dac04f2011-06-06 14:57:06 +03005001module_param_named(fwlog, fwlog_param, charp, 0);
5002MODULE_PARM_DESC(keymap,
5003 "FW logger options: continuous, ondemand, dbgpins or disable");
5004
Eliad Peller2a5bff02011-08-25 18:10:59 +03005005module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5006MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5007
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005008MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005009MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005010MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");