blob: f1fd9916e020696507348d5f08f256beb89d5a1b [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 */
269 .min_dwell_time_active = 8,
270 .max_dwell_time_active = 30,
271 .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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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{
773 bool fw_ps;
774
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);
780
781 /*
782 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300783 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300785 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200786 wl1271_ps_link_end(wl, hlid);
787
788 /* Start high-level PS if the STA is asleep with enough blocks in FW */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300789 else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200790 wl1271_ps_link_start(wl, hlid, true);
791}
792
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300793bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
794{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300795 int id;
796
797 /* global/broadcast "stations" are always active */
798 if (hlid < WL1271_AP_STA_HLID_START)
799 return true;
800
801 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300802 return test_bit(id, wl->ap_hlid_map);
803}
804
805static void wl12xx_irq_update_links_status(struct wl1271 *wl,
806 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200807{
808 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300809 u8 hlid, cnt;
810
811 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812
813 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
814 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
815 wl1271_debug(DEBUG_PSM,
816 "link ps prev 0x%x cur 0x%x changed 0x%x",
817 wl->ap_fw_ps_map, cur_fw_ps_map,
818 wl->ap_fw_ps_map ^ cur_fw_ps_map);
819
820 wl->ap_fw_ps_map = cur_fw_ps_map;
821 }
822
823 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300824 if (!wl1271_is_active_sta(wl, hlid))
825 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200826
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300827 cnt = status->tx_lnk_free_pkts[hlid] -
828 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200829
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300830 wl->links[hlid].prev_freed_pkts =
831 status->tx_lnk_free_pkts[hlid];
832 wl->links[hlid].allocated_pkts -= cnt;
833
834 wl12xx_irq_ps_regulate_link(wl, hlid,
835 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200836 }
837}
838
Eliad Peller4d56ad92011-08-14 13:17:05 +0300839static void wl12xx_fw_status(struct wl1271 *wl,
840 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200842 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200843 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300844 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300845 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846
Eliad Peller4d56ad92011-08-14 13:17:05 +0300847 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
850 "drv_rx_counter = %d, tx_results_counter = %d)",
851 status->intr,
852 status->fw_rx_counter,
853 status->drv_rx_counter,
854 status->tx_results_counter);
855
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300856 for (i = 0; i < NUM_TX_QUEUES; i++) {
857 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300858 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300859 (status->tx_released_pkts[i] -
860 wl->tx_pkts_freed[i]) & 0xff;
861
862 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
863 }
864
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300865 /* prevent wrap-around in total blocks counter */
866 if (likely(wl->tx_blocks_freed <=
867 le32_to_cpu(status->total_released_blks)))
868 freed_blocks = le32_to_cpu(status->total_released_blks) -
869 wl->tx_blocks_freed;
870 else
871 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
872 le32_to_cpu(status->total_released_blks);
873
Eliad Peller4d56ad92011-08-14 13:17:05 +0300874 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200875
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300876 wl->tx_allocated_blocks -= freed_blocks;
877
Eliad Peller4d56ad92011-08-14 13:17:05 +0300878 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200879
Eliad Peller4d56ad92011-08-14 13:17:05 +0300880 /*
881 * The FW might change the total number of TX memblocks before
882 * we get a notification about blocks being released. Thus, the
883 * available blocks calculation might yield a temporary result
884 * which is lower than the actual available blocks. Keeping in
885 * mind that only blocks that were allocated can be moved from
886 * TX to RX, tx_blocks_available should never decrease here.
887 */
888 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
889 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890
Ido Yariva5225502010-10-12 14:49:10 +0200891 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200892 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200893 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894
Eliad Peller4d56ad92011-08-14 13:17:05 +0300895 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300896 if (wl->bss_type == BSS_TYPE_AP_BSS)
897 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200900 getnstimeofday(&ts);
901 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
902 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903}
904
Ido Yariva6208652011-03-01 15:14:41 +0200905static void wl1271_flush_deferred_work(struct wl1271 *wl)
906{
907 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200908
Ido Yariva6208652011-03-01 15:14:41 +0200909 /* Pass all received frames to the network stack */
910 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
911 ieee80211_rx_ni(wl->hw, skb);
912
913 /* Return sent skbs to the network stack */
914 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300915 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200916}
917
918static void wl1271_netstack_work(struct work_struct *work)
919{
920 struct wl1271 *wl =
921 container_of(work, struct wl1271, netstack_work);
922
923 do {
924 wl1271_flush_deferred_work(wl);
925 } while (skb_queue_len(&wl->deferred_rx_queue));
926}
927
928#define WL1271_IRQ_MAX_LOOPS 256
929
930irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300933 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200934 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200935 struct wl1271 *wl = (struct wl1271 *)cookie;
936 bool done = false;
937 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 unsigned long flags;
939
940 /* TX might be handled here, avoid redundant work */
941 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
942 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943
Ido Yariv341b7cd2011-03-31 10:07:01 +0200944 /*
945 * In case edge triggered interrupt must be used, we cannot iterate
946 * more than once without introducing race conditions with the hardirq.
947 */
948 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
949 loopcount = 1;
950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 mutex_lock(&wl->mutex);
952
953 wl1271_debug(DEBUG_IRQ, "IRQ work");
954
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200955 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 goto out;
957
Ido Yariva6208652011-03-01 15:14:41 +0200958 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 if (ret < 0)
960 goto out;
961
Ido Yariva6208652011-03-01 15:14:41 +0200962 while (!done && loopcount--) {
963 /*
964 * In order to avoid a race with the hardirq, clear the flag
965 * before acknowledging the chip. Since the mutex is held,
966 * wl1271_ps_elp_wakeup cannot be called concurrently.
967 */
968 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
969 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200970
Eliad Peller4d56ad92011-08-14 13:17:05 +0300971 wl12xx_fw_status(wl, wl->fw_status);
972 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200973 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200974 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200975 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200976 continue;
977 }
978
Eliad Pellerccc83b02010-10-27 14:09:57 +0200979 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
980 wl1271_error("watchdog interrupt received! "
981 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300982 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200983
984 /* restarting the chip. ignore any other interrupt. */
985 goto out;
986 }
987
Ido Yariva6208652011-03-01 15:14:41 +0200988 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200989 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
990
Eliad Peller4d56ad92011-08-14 13:17:05 +0300991 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200992
Ido Yariva5225502010-10-12 14:49:10 +0200993 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200994 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200995 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300996 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200997 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200998 /*
999 * In order to avoid starvation of the TX path,
1000 * call the work function directly.
1001 */
1002 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001003 } else {
1004 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001005 }
1006
Ido Yariv8aad2462011-03-01 15:14:38 +02001007 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001008 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001009 (wl->tx_results_count & 0xff))
1010 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001011
1012 /* Make sure the deferred queues don't get too long */
1013 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1014 skb_queue_len(&wl->deferred_rx_queue);
1015 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1016 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001017 }
1018
1019 if (intr & WL1271_ACX_INTR_EVENT_A) {
1020 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1021 wl1271_event_handle(wl, 0);
1022 }
1023
1024 if (intr & WL1271_ACX_INTR_EVENT_B) {
1025 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1026 wl1271_event_handle(wl, 1);
1027 }
1028
1029 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1030 wl1271_debug(DEBUG_IRQ,
1031 "WL1271_ACX_INTR_INIT_COMPLETE");
1032
1033 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1034 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 }
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 wl1271_ps_elp_sleep(wl);
1038
1039out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001040 spin_lock_irqsave(&wl->wl_lock, flags);
1041 /* In case TX was not handled here, queue TX work */
1042 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1043 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001044 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001045 ieee80211_queue_work(wl->hw, &wl->tx_work);
1046 spin_unlock_irqrestore(&wl->wl_lock, flags);
1047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001049
1050 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051}
Ido Yariva6208652011-03-01 15:14:41 +02001052EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054static int wl1271_fetch_firmware(struct wl1271 *wl)
1055{
1056 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001057 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 int ret;
1059
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001060 if (wl->chip.id == CHIP_ID_1283_PG20)
1061 fw_name = WL128X_FW_NAME;
1062 else
1063 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001064
1065 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1066
1067 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 if (ret < 0) {
1070 wl1271_error("could not get firmware: %d", ret);
1071 return ret;
1072 }
1073
1074 if (fw->size % 4) {
1075 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1076 fw->size);
1077 ret = -EILSEQ;
1078 goto out;
1079 }
1080
Arik Nemtsov166d5042010-10-16 21:44:57 +02001081 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001083 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084
1085 if (!wl->fw) {
1086 wl1271_error("could not allocate memory for the firmware");
1087 ret = -ENOMEM;
1088 goto out;
1089 }
1090
1091 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 ret = 0;
1093
1094out:
1095 release_firmware(fw);
1096
1097 return ret;
1098}
1099
1100static int wl1271_fetch_nvs(struct wl1271 *wl)
1101{
1102 const struct firmware *fw;
1103 int ret;
1104
Shahar Levi5aa42342011-03-06 16:32:07 +02001105 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106
1107 if (ret < 0) {
1108 wl1271_error("could not get nvs file: %d", ret);
1109 return ret;
1110 }
1111
Shahar Levibc765bf2011-03-06 16:32:10 +02001112 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113
1114 if (!wl->nvs) {
1115 wl1271_error("could not allocate memory for the nvs file");
1116 ret = -ENOMEM;
1117 goto out;
1118 }
1119
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001120 wl->nvs_len = fw->size;
1121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122out:
1123 release_firmware(fw);
1124
1125 return ret;
1126}
1127
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001128void wl12xx_queue_recovery_work(struct wl1271 *wl)
1129{
1130 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1131 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1132}
1133
Ido Yariv95dac04f2011-06-06 14:57:06 +03001134size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1135{
1136 size_t len = 0;
1137
1138 /* The FW log is a length-value list, find where the log end */
1139 while (len < maxlen) {
1140 if (memblock[len] == 0)
1141 break;
1142 if (len + memblock[len] + 1 > maxlen)
1143 break;
1144 len += memblock[len] + 1;
1145 }
1146
1147 /* Make sure we have enough room */
1148 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1149
1150 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1151 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1152 wl->fwlog_size += len;
1153
1154 return len;
1155}
1156
1157static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1158{
1159 u32 addr;
1160 u32 first_addr;
1161 u8 *block;
1162
1163 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1164 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1165 (wl->conf.fwlog.mem_blocks == 0))
1166 return;
1167
1168 wl1271_info("Reading FW panic log");
1169
1170 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1171 if (!block)
1172 return;
1173
1174 /*
1175 * Make sure the chip is awake and the logger isn't active.
1176 * This might fail if the firmware hanged.
1177 */
1178 if (!wl1271_ps_elp_wakeup(wl))
1179 wl12xx_cmd_stop_fwlog(wl);
1180
1181 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001182 wl12xx_fw_status(wl, wl->fw_status);
1183 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001184 if (!first_addr)
1185 goto out;
1186
1187 /* Traverse the memory blocks linked list */
1188 addr = first_addr;
1189 do {
1190 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1191 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1192 false);
1193
1194 /*
1195 * Memory blocks are linked to one another. The first 4 bytes
1196 * of each memory block hold the hardware address of the next
1197 * one. The last memory block points to the first one.
1198 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001199 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001200 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1201 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1202 break;
1203 } while (addr && (addr != first_addr));
1204
1205 wake_up_interruptible(&wl->fwlog_waitq);
1206
1207out:
1208 kfree(block);
1209}
1210
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001211static void wl1271_recovery_work(struct work_struct *work)
1212{
1213 struct wl1271 *wl =
1214 container_of(work, struct wl1271, recovery_work);
1215
1216 mutex_lock(&wl->mutex);
1217
1218 if (wl->state != WL1271_STATE_ON)
1219 goto out;
1220
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001221 /* Avoid a recursive recovery */
1222 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1223
Ido Yariv95dac04f2011-06-06 14:57:06 +03001224 wl12xx_read_fwlog_panic(wl);
1225
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001226 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1227 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001228
Eliad Peller2a5bff02011-08-25 18:10:59 +03001229 BUG_ON(bug_on_recovery);
1230
Oz Krakowskib992c682011-06-26 10:36:02 +03001231 /*
1232 * Advance security sequence number to overcome potential progress
1233 * in the firmware during recovery. This doens't hurt if the network is
1234 * not encrypted.
1235 */
1236 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1237 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1238 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1239
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001240 /* Prevent spurious TX during FW restart */
1241 ieee80211_stop_queues(wl->hw);
1242
Luciano Coelho33c2c062011-05-10 14:46:02 +03001243 if (wl->sched_scanning) {
1244 ieee80211_sched_scan_stopped(wl->hw);
1245 wl->sched_scanning = false;
1246 }
1247
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001248 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001249 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
1260
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261out:
1262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 break;
1327 case CHIP_ID_1271_PG20:
1328 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1329 wl->chip.id);
1330
Shahar Levi0c005042011-06-12 10:34:43 +03001331 /*
1332 * 'end-of-transaction flag' and 'LPD mode flag'
1333 * should be set in wl127x AP mode only
1334 */
Shahar Levi564f5952011-04-04 10:20:39 +03001335 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001336 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1337 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 ret = wl1271_setup(wl);
1340 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001343 case CHIP_ID_1283_PG20:
1344 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1345 wl->chip.id);
1346
1347 ret = wl1271_setup(wl);
1348 if (ret < 0)
1349 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001350
Ido Yariv0da13da2011-03-31 10:06:58 +02001351 if (wl1271_set_block_size(wl))
1352 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001353 break;
1354 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 }
1360
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001361 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 ret = wl1271_fetch_firmware(wl);
1363 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001364 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 }
1366
1367 /* No NVS from netlink, try to get it from the filesystem */
1368 if (wl->nvs == NULL) {
1369 ret = wl1271_fetch_nvs(wl);
1370 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 }
1373
1374out:
1375 return ret;
1376}
1377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378int wl1271_plt_start(struct wl1271 *wl)
1379{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001380 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001381 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 int ret;
1383
1384 mutex_lock(&wl->mutex);
1385
1386 wl1271_notice("power up");
1387
1388 if (wl->state != WL1271_STATE_OFF) {
1389 wl1271_error("cannot go into PLT state because not "
1390 "in off state: %d", wl->state);
1391 ret = -EBUSY;
1392 goto out;
1393 }
1394
Arik Nemtsov166d5042010-10-16 21:44:57 +02001395 wl->bss_type = BSS_TYPE_STA_BSS;
1396
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 while (retries) {
1398 retries--;
1399 ret = wl1271_chip_wakeup(wl);
1400 if (ret < 0)
1401 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 ret = wl1271_boot(wl);
1404 if (ret < 0)
1405 goto power_off;
1406
1407 ret = wl1271_plt_init(wl);
1408 if (ret < 0)
1409 goto irq_disable;
1410
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 wl->state = WL1271_STATE_PLT;
1412 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001413 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001414
Gery Kahn6f07b722011-07-18 14:21:49 +03001415 /* update hw/fw version info in wiphy struct */
1416 wiphy->hw_version = wl->chip.id;
1417 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1418 sizeof(wiphy->fw_version));
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 goto out;
1421
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 mutex_unlock(&wl->mutex);
1424 /* Unlocking the mutex in the middle of handling is
1425 inherently unsafe. In this case we deem it safe to do,
1426 because we need to let any possibly pending IRQ out of
1427 the system (and while we are WL1271_STATE_OFF the IRQ
1428 work function will not do anything.) Also, any other
1429 possible concurrent operations will fail due to the
1430 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001431 wl1271_disable_interrupts(wl);
1432 wl1271_flush_deferred_work(wl);
1433 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001434 mutex_lock(&wl->mutex);
1435power_off:
1436 wl1271_power_off(wl);
1437 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1440 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441out:
1442 mutex_unlock(&wl->mutex);
1443
1444 return ret;
1445}
1446
Luciano Coelho4623ec72011-03-21 19:26:41 +02001447static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448{
1449 int ret = 0;
1450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 wl1271_notice("power down");
1452
1453 if (wl->state != WL1271_STATE_PLT) {
1454 wl1271_error("cannot power down because not in PLT "
1455 "state: %d", wl->state);
1456 ret = -EBUSY;
1457 goto out;
1458 }
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 wl1271_power_off(wl);
1461
1462 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001463 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001466 wl1271_disable_interrupts(wl);
1467 wl1271_flush_deferred_work(wl);
1468 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001469 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001470 mutex_lock(&wl->mutex);
1471out:
1472 return ret;
1473}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001474
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475int wl1271_plt_stop(struct wl1271 *wl)
1476{
1477 int ret;
1478
1479 mutex_lock(&wl->mutex);
1480 ret = __wl1271_plt_stop(wl);
1481 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 return ret;
1483}
1484
Johannes Berg7bb45682011-02-24 14:42:06 +01001485static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486{
1487 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001488 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001490 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001492 mapping = skb_get_queue_mapping(skb);
1493 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
1495 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001496 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001497
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001498 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001500 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001501 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001502 if (!wl1271_is_active_sta(wl, hlid)) {
1503 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1504 hlid, q);
1505 dev_kfree_skb(skb);
1506 goto out;
1507 }
1508
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001509 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1510 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1511 } else {
1512 skb_queue_tail(&wl->tx_queue[q], skb);
1513 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001515 wl->tx_queue_count[q]++;
1516
1517 /*
1518 * The workqueue is slow to process the tx_queue and we need stop
1519 * the queue here, otherwise the queue will get too long.
1520 */
1521 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1522 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1523 ieee80211_stop_queue(wl->hw, mapping);
1524 set_bit(q, &wl->stopped_queues_map);
1525 }
1526
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 /*
1528 * The chip specific setup must run before the first TX packet -
1529 * before that, the tx_work will not be initialized!
1530 */
1531
Ido Yarivb07d4032011-03-01 15:14:43 +02001532 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1533 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001534 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001535
Arik Nemtsov04216da2011-08-14 13:17:38 +03001536out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001537 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538}
1539
Shahar Leviae47c452011-03-06 16:32:14 +02001540int wl1271_tx_dummy_packet(struct wl1271 *wl)
1541{
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001543 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001544
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 spin_lock_irqsave(&wl->wl_lock, flags);
1546 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001547 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001548 spin_unlock_irqrestore(&wl->wl_lock, flags);
1549
1550 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1551 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1552 wl1271_tx_work_locked(wl);
1553
1554 /*
1555 * If the FW TX is busy, TX work will be scheduled by the threaded
1556 * interrupt handler function
1557 */
1558 return 0;
1559}
1560
1561/*
1562 * The size of the dummy packet should be at least 1400 bytes. However, in
1563 * order to minimize the number of bus transactions, aligning it to 512 bytes
1564 * boundaries could be beneficial, performance wise
1565 */
1566#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1567
Luciano Coelhocf27d862011-04-01 21:08:23 +03001568static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001569{
1570 struct sk_buff *skb;
1571 struct ieee80211_hdr_3addr *hdr;
1572 unsigned int dummy_packet_size;
1573
1574 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1575 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1576
1577 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001578 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001579 wl1271_warning("Failed to allocate a dummy packet skb");
1580 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001581 }
1582
1583 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1584
1585 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1586 memset(hdr, 0, sizeof(*hdr));
1587 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 IEEE80211_STYPE_NULLFUNC |
1589 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001590
Ido Yariv990f5de2011-03-31 10:06:59 +02001591 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001592
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001593 /* Dummy packets require the TID to be management */
1594 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001595
1596 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001597 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001598 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001599
Ido Yariv990f5de2011-03-31 10:06:59 +02001600 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001601}
1602
Ido Yariv990f5de2011-03-31 10:06:59 +02001603
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001604static struct notifier_block wl1271_dev_notifier = {
1605 .notifier_call = wl1271_dev_notify,
1606};
1607
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001608#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001609static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001610{
Eliad Pellere85d1622011-06-27 13:06:43 +03001611 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001612
Eliad Peller94390642011-05-13 11:57:13 +03001613 mutex_lock(&wl->mutex);
1614
Eliad Pellere85d1622011-06-27 13:06:43 +03001615 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1616 goto out_unlock;
1617
Eliad Peller94390642011-05-13 11:57:13 +03001618 ret = wl1271_ps_elp_wakeup(wl);
1619 if (ret < 0)
1620 goto out_unlock;
1621
1622 /* enter psm if needed*/
1623 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1624 DECLARE_COMPLETION_ONSTACK(compl);
1625
1626 wl->ps_compl = &compl;
1627 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1628 wl->basic_rate, true);
1629 if (ret < 0)
1630 goto out_sleep;
1631
1632 /* we must unlock here so we will be able to get events */
1633 wl1271_ps_elp_sleep(wl);
1634 mutex_unlock(&wl->mutex);
1635
1636 ret = wait_for_completion_timeout(
1637 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1638 if (ret <= 0) {
1639 wl1271_warning("couldn't enter ps mode!");
1640 ret = -EBUSY;
1641 goto out;
1642 }
1643
1644 /* take mutex again, and wakeup */
1645 mutex_lock(&wl->mutex);
1646
1647 ret = wl1271_ps_elp_wakeup(wl);
1648 if (ret < 0)
1649 goto out_unlock;
1650 }
1651out_sleep:
1652 wl1271_ps_elp_sleep(wl);
1653out_unlock:
1654 mutex_unlock(&wl->mutex);
1655out:
1656 return ret;
1657
1658}
1659
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001661{
Eliad Pellere85d1622011-06-27 13:06:43 +03001662 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001663
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664 mutex_lock(&wl->mutex);
1665
Eliad Pellere85d1622011-06-27 13:06:43 +03001666 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1667 goto out_unlock;
1668
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
1671 goto out_unlock;
1672
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001673 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001674
1675 wl1271_ps_elp_sleep(wl);
1676out_unlock:
1677 mutex_unlock(&wl->mutex);
1678 return ret;
1679
1680}
1681
1682static int wl1271_configure_suspend(struct wl1271 *wl)
1683{
1684 if (wl->bss_type == BSS_TYPE_STA_BSS)
1685 return wl1271_configure_suspend_sta(wl);
1686 if (wl->bss_type == BSS_TYPE_AP_BSS)
1687 return wl1271_configure_suspend_ap(wl);
1688 return 0;
1689}
1690
1691static void wl1271_configure_resume(struct wl1271 *wl)
1692{
1693 int ret;
1694 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1695 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1696
1697 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001698 return;
1699
1700 mutex_lock(&wl->mutex);
1701 ret = wl1271_ps_elp_wakeup(wl);
1702 if (ret < 0)
1703 goto out;
1704
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001705 if (is_sta) {
1706 /* exit psm if it wasn't configured */
1707 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1708 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1709 wl->basic_rate, true);
1710 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001711 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001712 }
Eliad Peller94390642011-05-13 11:57:13 +03001713
1714 wl1271_ps_elp_sleep(wl);
1715out:
1716 mutex_unlock(&wl->mutex);
1717}
1718
Eliad Peller402e48612011-05-13 11:57:09 +03001719static int wl1271_op_suspend(struct ieee80211_hw *hw,
1720 struct cfg80211_wowlan *wow)
1721{
1722 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001723 int ret;
1724
Eliad Peller402e48612011-05-13 11:57:09 +03001725 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001727
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 wl->wow_enabled = true;
1729 ret = wl1271_configure_suspend(wl);
1730 if (ret < 0) {
1731 wl1271_warning("couldn't prepare device to suspend");
1732 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001733 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 /* flush any remaining work */
1735 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001736
1737 /*
1738 * disable and re-enable interrupts in order to flush
1739 * the threaded_irq
1740 */
1741 wl1271_disable_interrupts(wl);
1742
1743 /*
1744 * set suspended flag to avoid triggering a new threaded_irq
1745 * work. no need for spinlock as interrupts are disabled.
1746 */
1747 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1748
1749 wl1271_enable_interrupts(wl);
1750 flush_work(&wl->tx_work);
1751 flush_delayed_work(&wl->pspoll_work);
1752 flush_delayed_work(&wl->elp_work);
1753
Eliad Peller402e48612011-05-13 11:57:09 +03001754 return 0;
1755}
1756
1757static int wl1271_op_resume(struct ieee80211_hw *hw)
1758{
1759 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001760 unsigned long flags;
1761 bool run_irq_work = false;
1762
Eliad Peller402e48612011-05-13 11:57:09 +03001763 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1764 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001765 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001766
1767 /*
1768 * re-enable irq_work enqueuing, and call irq_work directly if
1769 * there is a pending work.
1770 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 spin_lock_irqsave(&wl->wl_lock, flags);
1772 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1773 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1774 run_irq_work = true;
1775 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001776
Eliad Peller4a859df2011-06-06 12:21:52 +03001777 if (run_irq_work) {
1778 wl1271_debug(DEBUG_MAC80211,
1779 "run postponed irq_work directly");
1780 wl1271_irq(0, wl);
1781 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001782 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001783 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001784 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001785
Eliad Peller402e48612011-05-13 11:57:09 +03001786 return 0;
1787}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001788#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001790static int wl1271_op_start(struct ieee80211_hw *hw)
1791{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001792 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1793
1794 /*
1795 * We have to delay the booting of the hardware because
1796 * we need to know the local MAC address before downloading and
1797 * initializing the firmware. The MAC address cannot be changed
1798 * after boot, and without the proper MAC address, the firmware
1799 * will not function properly.
1800 *
1801 * The MAC address is first known when the corresponding interface
1802 * is added. That is where we will initialize the hardware.
1803 */
1804
1805 return 0;
1806}
1807
1808static void wl1271_op_stop(struct ieee80211_hw *hw)
1809{
1810 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1811}
1812
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001813static u8 wl12xx_get_role_type(struct wl1271 *wl)
1814{
1815 switch (wl->bss_type) {
1816 case BSS_TYPE_AP_BSS:
1817 return WL1271_ROLE_AP;
1818
1819 case BSS_TYPE_STA_BSS:
1820 return WL1271_ROLE_STA;
1821
Eliad Peller227e81e2011-08-14 13:17:26 +03001822 case BSS_TYPE_IBSS:
1823 return WL1271_ROLE_IBSS;
1824
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001825 default:
1826 wl1271_error("invalid bss_type: %d", wl->bss_type);
1827 }
1828 return WL12XX_INVALID_ROLE_TYPE;
1829}
1830
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001831static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1832 struct ieee80211_vif *vif)
1833{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001835 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001836 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001838 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001839 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001841 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1842 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843
1844 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001845 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001846 wl1271_debug(DEBUG_MAC80211,
1847 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001848 ret = -EBUSY;
1849 goto out;
1850 }
1851
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001852 /*
1853 * in some very corner case HW recovery scenarios its possible to
1854 * get here before __wl1271_op_remove_interface is complete, so
1855 * opt out if that is the case.
1856 */
1857 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1858 ret = -EBUSY;
1859 goto out;
1860 }
1861
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001862 switch (vif->type) {
1863 case NL80211_IFTYPE_STATION:
1864 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001865 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001866 break;
1867 case NL80211_IFTYPE_ADHOC:
1868 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001869 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001870 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001871 case NL80211_IFTYPE_AP:
1872 wl->bss_type = BSS_TYPE_AP_BSS;
1873 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001874 default:
1875 ret = -EOPNOTSUPP;
1876 goto out;
1877 }
1878
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001879 role_type = wl12xx_get_role_type(wl);
1880 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1881 ret = -EINVAL;
1882 goto out;
1883 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001884 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001885
1886 if (wl->state != WL1271_STATE_OFF) {
1887 wl1271_error("cannot start because not in off state: %d",
1888 wl->state);
1889 ret = -EBUSY;
1890 goto out;
1891 }
1892
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001893 while (retries) {
1894 retries--;
1895 ret = wl1271_chip_wakeup(wl);
1896 if (ret < 0)
1897 goto power_off;
1898
1899 ret = wl1271_boot(wl);
1900 if (ret < 0)
1901 goto power_off;
1902
Eliad Peller227e81e2011-08-14 13:17:26 +03001903 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1904 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001905 /*
1906 * The device role is a special role used for
1907 * rx and tx frames prior to association (as
1908 * the STA role can get packets only from
1909 * its associated bssid)
1910 */
1911 ret = wl12xx_cmd_role_enable(wl,
1912 WL1271_ROLE_DEVICE,
1913 &wl->dev_role_id);
1914 if (ret < 0)
1915 goto irq_disable;
1916 }
1917
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001918 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1919 if (ret < 0)
1920 goto irq_disable;
1921
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001922 ret = wl1271_hw_init(wl);
1923 if (ret < 0)
1924 goto irq_disable;
1925
Eliad Peller71125ab2010-10-28 21:46:43 +02001926 booted = true;
1927 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001929irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001930 mutex_unlock(&wl->mutex);
1931 /* Unlocking the mutex in the middle of handling is
1932 inherently unsafe. In this case we deem it safe to do,
1933 because we need to let any possibly pending IRQ out of
1934 the system (and while we are WL1271_STATE_OFF the IRQ
1935 work function will not do anything.) Also, any other
1936 possible concurrent operations will fail due to the
1937 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001938 wl1271_disable_interrupts(wl);
1939 wl1271_flush_deferred_work(wl);
1940 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001941 mutex_lock(&wl->mutex);
1942power_off:
1943 wl1271_power_off(wl);
1944 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945
Eliad Peller71125ab2010-10-28 21:46:43 +02001946 if (!booted) {
1947 wl1271_error("firmware boot failed despite %d retries",
1948 WL1271_BOOT_RETRIES);
1949 goto out;
1950 }
1951
1952 wl->vif = vif;
1953 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001954 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001955 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001956
1957 /* update hw/fw version info in wiphy struct */
1958 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001959 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001960 sizeof(wiphy->fw_version));
1961
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001962 /*
1963 * Now we know if 11a is supported (info from the NVS), so disable
1964 * 11a channels if not supported
1965 */
1966 if (!wl->enable_11a)
1967 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1968
1969 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1970 wl->enable_11a ? "" : "not ");
1971
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001972out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973 mutex_unlock(&wl->mutex);
1974
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001975 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001976 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001977 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001978 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 return ret;
1981}
1982
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001983static void __wl1271_op_remove_interface(struct wl1271 *wl,
1984 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001986 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001988 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001990 /* because of hardware recovery, we may get here twice */
1991 if (wl->state != WL1271_STATE_ON)
1992 return;
1993
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001994 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001996 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001997 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001998 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001999
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002000 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03002001 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002002 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002003
Luciano Coelho08688d62010-07-08 17:50:07 +03002004 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002005 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002006 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002007 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002008 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 }
2010
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002011 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2012 /* disable active roles */
2013 ret = wl1271_ps_elp_wakeup(wl);
2014 if (ret < 0)
2015 goto deinit;
2016
Eliad Peller04e80792011-08-14 13:17:09 +03002017 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2018 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2019 if (ret < 0)
2020 goto deinit;
2021 }
2022
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002023 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2024 if (ret < 0)
2025 goto deinit;
2026
2027 wl1271_ps_elp_sleep(wl);
2028 }
2029deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002030 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002031 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002032 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002033 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2034 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002035
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002036 /*
2037 * this must be before the cancel_work calls below, so that the work
2038 * functions don't perform further work.
2039 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 wl->state = WL1271_STATE_OFF;
2041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042 mutex_unlock(&wl->mutex);
2043
Ido Yariva6208652011-03-01 15:14:41 +02002044 wl1271_disable_interrupts(wl);
2045 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002046 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002047 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002049 del_timer_sync(&wl->rx_streaming_timer);
2050 cancel_work_sync(&wl->rx_streaming_enable_work);
2051 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002052 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002053 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054
2055 mutex_lock(&wl->mutex);
2056
2057 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002058 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl1271_power_off(wl);
2060
2061 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002062 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002065 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002066 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067
2068 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002069 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2071 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002072 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073 wl->tx_results_count = 0;
2074 wl->tx_packets_count = 0;
2075 wl->time_offset = 0;
2076 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002077 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002078 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002079 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002080 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002081 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002082 wl->ap_fw_ps_map = 0;
2083 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002084 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002085 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002086 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002087 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2088 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002089 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002090
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002091 /* The system link is always allocated */
2092 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2093
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002094 /*
2095 * this is performed after the cancel_work calls and the associated
2096 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2097 * get executed before all these vars have been reset.
2098 */
2099 wl->flags = 0;
2100
Eliad Peller4d56ad92011-08-14 13:17:05 +03002101 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102
Arik Nemtsov742246f2011-08-14 13:17:33 +03002103 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002104 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002105 wl->tx_allocated_pkts[i] = 0;
2106 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002107
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002109
2110 kfree(wl->fw_status);
2111 wl->fw_status = NULL;
2112 kfree(wl->tx_res_if);
2113 wl->tx_res_if = NULL;
2114 kfree(wl->target_mem_map);
2115 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002116}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002117
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002118static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2119 struct ieee80211_vif *vif)
2120{
2121 struct wl1271 *wl = hw->priv;
2122
2123 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002124 /*
2125 * wl->vif can be null here if someone shuts down the interface
2126 * just when hardware recovery has been started.
2127 */
2128 if (wl->vif) {
2129 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002130 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002131 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002132
Juuso Oikarinen67353292010-11-18 15:19:02 +02002133 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002134 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135}
2136
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002137static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002138{
2139 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002140 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002141
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002142 /*
2143 * One of the side effects of the JOIN command is that is clears
2144 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2145 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002146 * Currently the only valid scenario for JOIN during association
2147 * is on roaming, in which case we will also be given new keys.
2148 * Keep the below message for now, unless it starts bothering
2149 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002150 */
2151 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2152 wl1271_info("JOIN while associated.");
2153
2154 if (set_assoc)
2155 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2156
Eliad Peller227e81e2011-08-14 13:17:26 +03002157 if (is_ibss)
2158 ret = wl12xx_cmd_role_start_ibss(wl);
2159 else
2160 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002161 if (ret < 0)
2162 goto out;
2163
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002164 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2165 goto out;
2166
2167 /*
2168 * The join command disable the keep-alive mode, shut down its process,
2169 * and also clear the template config, so we need to reset it all after
2170 * the join. The acx_aid starts the keep-alive process, and the order
2171 * of the commands below is relevant.
2172 */
2173 ret = wl1271_acx_keep_alive_mode(wl, true);
2174 if (ret < 0)
2175 goto out;
2176
2177 ret = wl1271_acx_aid(wl, wl->aid);
2178 if (ret < 0)
2179 goto out;
2180
2181 ret = wl1271_cmd_build_klv_null_data(wl);
2182 if (ret < 0)
2183 goto out;
2184
2185 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2186 ACX_KEEP_ALIVE_TPL_VALID);
2187 if (ret < 0)
2188 goto out;
2189
2190out:
2191 return ret;
2192}
2193
2194static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002195{
2196 int ret;
2197
2198 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002199 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002200 if (ret < 0)
2201 goto out;
2202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002203 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002204
Oz Krakowskib992c682011-06-26 10:36:02 +03002205 /* reset TX security counters on a clean disconnect */
2206 wl->tx_security_last_seq_lsb = 0;
2207 wl->tx_security_seq = 0;
2208
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002209out:
2210 return ret;
2211}
2212
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002213static void wl1271_set_band_rate(struct wl1271 *wl)
2214{
Eliad Peller53835a22011-08-23 15:56:23 +03002215 if (wl->band == IEEE80211_BAND_2GHZ) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002216 wl->basic_rate_set = wl->conf.tx.basic_rate;
Eliad Peller53835a22011-08-23 15:56:23 +03002217 wl->rate_set = wl->conf.tx.basic_rate;
2218 } else {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002219 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
Eliad Peller53835a22011-08-23 15:56:23 +03002220 wl->rate_set = wl->conf.tx.basic_rate_5;
2221 }
2222
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002223}
2224
Eliad Peller251c1772011-08-14 13:17:17 +03002225static bool wl12xx_is_roc(struct wl1271 *wl)
2226{
2227 u8 role_id;
2228
2229 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2230 if (role_id >= WL12XX_MAX_ROLES)
2231 return false;
2232
2233 return true;
2234}
2235
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002236static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002237{
2238 int ret;
2239
2240 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002241 /* no need to croc if we weren't busy (e.g. during boot) */
2242 if (wl12xx_is_roc(wl)) {
2243 ret = wl12xx_croc(wl, wl->dev_role_id);
2244 if (ret < 0)
2245 goto out;
2246
2247 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002248 if (ret < 0)
2249 goto out;
2250 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002251 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002252 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002253 if (ret < 0)
2254 goto out;
2255 ret = wl1271_acx_keep_alive_config(
2256 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2257 ACX_KEEP_ALIVE_TPL_INVALID);
2258 if (ret < 0)
2259 goto out;
2260 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2261 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002262 /* The current firmware only supports sched_scan in idle */
2263 if (wl->sched_scanning) {
2264 wl1271_scan_sched_scan_stop(wl);
2265 ieee80211_sched_scan_stopped(wl->hw);
2266 }
2267
Eliad Peller251c1772011-08-14 13:17:17 +03002268 ret = wl12xx_cmd_role_start_dev(wl);
2269 if (ret < 0)
2270 goto out;
2271
2272 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002273 if (ret < 0)
2274 goto out;
2275 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2276 }
2277
2278out:
2279 return ret;
2280}
2281
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002282static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2283{
2284 struct wl1271 *wl = hw->priv;
2285 struct ieee80211_conf *conf = &hw->conf;
2286 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002287 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288
2289 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2290
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002291 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2292 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293 channel,
2294 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002295 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002296 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2297 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002299 /*
2300 * mac80211 will go to idle nearly immediately after transmitting some
2301 * frames, such as the deauth. To make sure those frames reach the air,
2302 * wait here until the TX queue is fully flushed.
2303 */
2304 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2305 (conf->flags & IEEE80211_CONF_IDLE))
2306 wl1271_tx_flush(wl);
2307
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308 mutex_lock(&wl->mutex);
2309
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002310 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002311 /* we support configuring the channel and band while off */
2312 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2313 wl->band = conf->channel->band;
2314 wl->channel = channel;
2315 }
2316
Arik Nemtsov097f8822011-06-27 22:06:34 +03002317 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2318 wl->power_level = conf->power_level;
2319
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002320 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002321 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002322
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002323 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2324
Ido Yariva6208652011-03-01 15:14:41 +02002325 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002326 if (ret < 0)
2327 goto out;
2328
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002329 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002330 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2331 ((wl->band != conf->channel->band) ||
2332 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333 wl->band = conf->channel->band;
2334 wl->channel = channel;
2335
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002336 if (!is_ap) {
2337 /*
2338 * FIXME: the mac80211 should really provide a fixed
2339 * rate to use here. for now, just use the smallest
2340 * possible rate for the band as a fixed rate for
2341 * association frames and other control messages.
2342 */
2343 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2344 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002345
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002346 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2347 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002348 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002349 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002350 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002351
Eliad Peller251c1772011-08-14 13:17:17 +03002352 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2353 if (wl12xx_is_roc(wl)) {
2354 /* roaming */
2355 ret = wl12xx_croc(wl, wl->dev_role_id);
2356 if (ret < 0)
2357 goto out_sleep;
2358 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002359 ret = wl1271_join(wl, false);
2360 if (ret < 0)
2361 wl1271_warning("cmd join on channel "
2362 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002363 } else {
2364 /*
2365 * change the ROC channel. do it only if we are
2366 * not idle. otherwise, CROC will be called
2367 * anyway.
2368 */
2369 if (wl12xx_is_roc(wl) &&
2370 !(conf->flags & IEEE80211_CONF_IDLE)) {
2371 ret = wl12xx_croc(wl, wl->dev_role_id);
2372 if (ret < 0)
2373 goto out_sleep;
2374
2375 ret = wl12xx_roc(wl, wl->dev_role_id);
2376 if (ret < 0)
2377 wl1271_warning("roc failed %d",
2378 ret);
2379 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002380 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002381 }
2382 }
2383
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002384 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2385 ret = wl1271_sta_handle_idle(wl,
2386 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002387 if (ret < 0)
2388 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389 }
2390
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002391 /*
2392 * if mac80211 changes the PSM mode, make sure the mode is not
2393 * incorrectly changed after the pspoll failure active window.
2394 */
2395 if (changed & IEEE80211_CONF_CHANGE_PS)
2396 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2397
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002398 if (conf->flags & IEEE80211_CONF_PS &&
2399 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2400 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002401
2402 /*
2403 * We enter PSM only if we're already associated.
2404 * If we're not, we'll enter it when joining an SSID,
2405 * through the bss_info_changed() hook.
2406 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002407 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002408 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002409 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002410 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002411 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002412 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002413 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002414 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002415
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002416 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002417
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002418 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002419 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002420 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002421 }
2422
2423 if (conf->power_level != wl->power_level) {
2424 ret = wl1271_acx_tx_power(wl, conf->power_level);
2425 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002426 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427
2428 wl->power_level = conf->power_level;
2429 }
2430
2431out_sleep:
2432 wl1271_ps_elp_sleep(wl);
2433
2434out:
2435 mutex_unlock(&wl->mutex);
2436
2437 return ret;
2438}
2439
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002440struct wl1271_filter_params {
2441 bool enabled;
2442 int mc_list_length;
2443 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2444};
2445
Jiri Pirko22bedad32010-04-01 21:22:57 +00002446static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2447 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002448{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002449 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002450 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002451 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002452
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002453 if (unlikely(wl->state == WL1271_STATE_OFF))
2454 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002455
Juuso Oikarinen74441132009-10-13 12:47:53 +03002456 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002457 if (!fp) {
2458 wl1271_error("Out of memory setting filters.");
2459 return 0;
2460 }
2461
2462 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002463 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002464 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2465 fp->enabled = false;
2466 } else {
2467 fp->enabled = true;
2468 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002469 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002470 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002471 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002472 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002473 }
2474
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002475 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002476}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002478#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2479 FIF_ALLMULTI | \
2480 FIF_FCSFAIL | \
2481 FIF_BCN_PRBRESP_PROMISC | \
2482 FIF_CONTROL | \
2483 FIF_OTHER_BSS)
2484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2486 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002487 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002488{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002489 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002491 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492
Arik Nemtsov7d057862010-10-16 19:25:35 +02002493 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2494 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002496 mutex_lock(&wl->mutex);
2497
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002498 *total &= WL1271_SUPPORTED_FILTERS;
2499 changed &= WL1271_SUPPORTED_FILTERS;
2500
2501 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002502 goto out;
2503
Ido Yariva6208652011-03-01 15:14:41 +02002504 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002505 if (ret < 0)
2506 goto out;
2507
Arik Nemtsov7d057862010-10-16 19:25:35 +02002508 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2509 if (*total & FIF_ALLMULTI)
2510 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2511 else if (fp)
2512 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2513 fp->mc_list,
2514 fp->mc_list_length);
2515 if (ret < 0)
2516 goto out_sleep;
2517 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002519 /*
2520 * the fw doesn't provide an api to configure the filters. instead,
2521 * the filters configuration is based on the active roles / ROC
2522 * state.
2523 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002524
2525out_sleep:
2526 wl1271_ps_elp_sleep(wl);
2527
2528out:
2529 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002530 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531}
2532
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002533static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2534 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2535 u16 tx_seq_16)
2536{
2537 struct wl1271_ap_key *ap_key;
2538 int i;
2539
2540 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2541
2542 if (key_size > MAX_KEY_SIZE)
2543 return -EINVAL;
2544
2545 /*
2546 * Find next free entry in ap_keys. Also check we are not replacing
2547 * an existing key.
2548 */
2549 for (i = 0; i < MAX_NUM_KEYS; i++) {
2550 if (wl->recorded_ap_keys[i] == NULL)
2551 break;
2552
2553 if (wl->recorded_ap_keys[i]->id == id) {
2554 wl1271_warning("trying to record key replacement");
2555 return -EINVAL;
2556 }
2557 }
2558
2559 if (i == MAX_NUM_KEYS)
2560 return -EBUSY;
2561
2562 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2563 if (!ap_key)
2564 return -ENOMEM;
2565
2566 ap_key->id = id;
2567 ap_key->key_type = key_type;
2568 ap_key->key_size = key_size;
2569 memcpy(ap_key->key, key, key_size);
2570 ap_key->hlid = hlid;
2571 ap_key->tx_seq_32 = tx_seq_32;
2572 ap_key->tx_seq_16 = tx_seq_16;
2573
2574 wl->recorded_ap_keys[i] = ap_key;
2575 return 0;
2576}
2577
2578static void wl1271_free_ap_keys(struct wl1271 *wl)
2579{
2580 int i;
2581
2582 for (i = 0; i < MAX_NUM_KEYS; i++) {
2583 kfree(wl->recorded_ap_keys[i]);
2584 wl->recorded_ap_keys[i] = NULL;
2585 }
2586}
2587
2588static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2589{
2590 int i, ret = 0;
2591 struct wl1271_ap_key *key;
2592 bool wep_key_added = false;
2593
2594 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002595 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002596 if (wl->recorded_ap_keys[i] == NULL)
2597 break;
2598
2599 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002600 hlid = key->hlid;
2601 if (hlid == WL12XX_INVALID_LINK_ID)
2602 hlid = wl->ap_bcast_hlid;
2603
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002604 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2605 key->id, key->key_type,
2606 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002607 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002608 key->tx_seq_16);
2609 if (ret < 0)
2610 goto out;
2611
2612 if (key->key_type == KEY_WEP)
2613 wep_key_added = true;
2614 }
2615
2616 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002617 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002618 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002619 if (ret < 0)
2620 goto out;
2621 }
2622
2623out:
2624 wl1271_free_ap_keys(wl);
2625 return ret;
2626}
2627
2628static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2629 u8 key_size, const u8 *key, u32 tx_seq_32,
2630 u16 tx_seq_16, struct ieee80211_sta *sta)
2631{
2632 int ret;
2633 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2634
2635 if (is_ap) {
2636 struct wl1271_station *wl_sta;
2637 u8 hlid;
2638
2639 if (sta) {
2640 wl_sta = (struct wl1271_station *)sta->drv_priv;
2641 hlid = wl_sta->hlid;
2642 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002643 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002644 }
2645
2646 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2647 /*
2648 * We do not support removing keys after AP shutdown.
2649 * Pretend we do to make mac80211 happy.
2650 */
2651 if (action != KEY_ADD_OR_REPLACE)
2652 return 0;
2653
2654 ret = wl1271_record_ap_key(wl, id,
2655 key_type, key_size,
2656 key, hlid, tx_seq_32,
2657 tx_seq_16);
2658 } else {
2659 ret = wl1271_cmd_set_ap_key(wl, action,
2660 id, key_type, key_size,
2661 key, hlid, tx_seq_32,
2662 tx_seq_16);
2663 }
2664
2665 if (ret < 0)
2666 return ret;
2667 } else {
2668 const u8 *addr;
2669 static const u8 bcast_addr[ETH_ALEN] = {
2670 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2671 };
2672
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002673 /*
2674 * A STA set to GEM cipher requires 2 tx spare blocks.
2675 * Return to default value when GEM cipher key is removed
2676 */
2677 if (key_type == KEY_GEM) {
2678 if (action == KEY_ADD_OR_REPLACE)
2679 wl->tx_spare_blocks = 2;
2680 else if (action == KEY_REMOVE)
2681 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2682 }
2683
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002684 addr = sta ? sta->addr : bcast_addr;
2685
2686 if (is_zero_ether_addr(addr)) {
2687 /* We dont support TX only encryption */
2688 return -EOPNOTSUPP;
2689 }
2690
2691 /* The wl1271 does not allow to remove unicast keys - they
2692 will be cleared automatically on next CMD_JOIN. Ignore the
2693 request silently, as we dont want the mac80211 to emit
2694 an error message. */
2695 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2696 return 0;
2697
Eliad Peller010d3d32011-08-14 13:17:31 +03002698 /* don't remove key if hlid was already deleted */
2699 if (action == KEY_REMOVE &&
2700 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2701 return 0;
2702
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002703 ret = wl1271_cmd_set_sta_key(wl, action,
2704 id, key_type, key_size,
2705 key, addr, tx_seq_32,
2706 tx_seq_16);
2707 if (ret < 0)
2708 return ret;
2709
2710 /* the default WEP key needs to be configured at least once */
2711 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002712 ret = wl12xx_cmd_set_default_wep_key(wl,
2713 wl->default_key,
2714 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002715 if (ret < 0)
2716 return ret;
2717 }
2718 }
2719
2720 return 0;
2721}
2722
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002723static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2724 struct ieee80211_vif *vif,
2725 struct ieee80211_sta *sta,
2726 struct ieee80211_key_conf *key_conf)
2727{
2728 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002729 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002730 u32 tx_seq_32 = 0;
2731 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732 u8 key_type;
2733
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2735
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002736 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002738 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002739 key_conf->keylen, key_conf->flags);
2740 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2741
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002742 mutex_lock(&wl->mutex);
2743
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002744 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2745 ret = -EAGAIN;
2746 goto out_unlock;
2747 }
2748
Ido Yariva6208652011-03-01 15:14:41 +02002749 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002750 if (ret < 0)
2751 goto out_unlock;
2752
Johannes Berg97359d12010-08-10 09:46:38 +02002753 switch (key_conf->cipher) {
2754 case WLAN_CIPHER_SUITE_WEP40:
2755 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002756 key_type = KEY_WEP;
2757
2758 key_conf->hw_key_idx = key_conf->keyidx;
2759 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002760 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761 key_type = KEY_TKIP;
2762
2763 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002764 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2765 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002767 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002768 key_type = KEY_AES;
2769
2770 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002771 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2772 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002773 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002774 case WL1271_CIPHER_SUITE_GEM:
2775 key_type = KEY_GEM;
2776 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2777 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2778 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002779 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002780 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002781
2782 ret = -EOPNOTSUPP;
2783 goto out_sleep;
2784 }
2785
2786 switch (cmd) {
2787 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002788 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2789 key_conf->keyidx, key_type,
2790 key_conf->keylen, key_conf->key,
2791 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002792 if (ret < 0) {
2793 wl1271_error("Could not add or replace key");
2794 goto out_sleep;
2795 }
2796 break;
2797
2798 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002799 ret = wl1271_set_key(wl, KEY_REMOVE,
2800 key_conf->keyidx, key_type,
2801 key_conf->keylen, key_conf->key,
2802 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002803 if (ret < 0) {
2804 wl1271_error("Could not remove key");
2805 goto out_sleep;
2806 }
2807 break;
2808
2809 default:
2810 wl1271_error("Unsupported key cmd 0x%x", cmd);
2811 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002812 break;
2813 }
2814
2815out_sleep:
2816 wl1271_ps_elp_sleep(wl);
2817
2818out_unlock:
2819 mutex_unlock(&wl->mutex);
2820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 return ret;
2822}
2823
2824static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002825 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826 struct cfg80211_scan_request *req)
2827{
2828 struct wl1271 *wl = hw->priv;
2829 int ret;
2830 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002831 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832
2833 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2834
2835 if (req->n_ssids) {
2836 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002837 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838 }
2839
2840 mutex_lock(&wl->mutex);
2841
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002842 if (wl->state == WL1271_STATE_OFF) {
2843 /*
2844 * We cannot return -EBUSY here because cfg80211 will expect
2845 * a call to ieee80211_scan_completed if we do - in this case
2846 * there won't be any call.
2847 */
2848 ret = -EAGAIN;
2849 goto out;
2850 }
2851
Ido Yariva6208652011-03-01 15:14:41 +02002852 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002853 if (ret < 0)
2854 goto out;
2855
Eliad Peller251c1772011-08-14 13:17:17 +03002856 /* cancel ROC before scanning */
2857 if (wl12xx_is_roc(wl)) {
2858 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2859 /* don't allow scanning right now */
2860 ret = -EBUSY;
2861 goto out_sleep;
2862 }
2863 wl12xx_croc(wl, wl->dev_role_id);
2864 wl12xx_cmd_role_stop_dev(wl);
2865 }
2866
Luciano Coelho5924f892010-08-04 03:46:22 +03002867 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002868out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002869 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002870out:
2871 mutex_unlock(&wl->mutex);
2872
2873 return ret;
2874}
2875
Eliad Peller73ecce32011-06-27 13:06:45 +03002876static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2877 struct ieee80211_vif *vif)
2878{
2879 struct wl1271 *wl = hw->priv;
2880 int ret;
2881
2882 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2883
2884 mutex_lock(&wl->mutex);
2885
2886 if (wl->state == WL1271_STATE_OFF)
2887 goto out;
2888
2889 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2890 goto out;
2891
2892 ret = wl1271_ps_elp_wakeup(wl);
2893 if (ret < 0)
2894 goto out;
2895
2896 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2897 ret = wl1271_scan_stop(wl);
2898 if (ret < 0)
2899 goto out_sleep;
2900 }
2901 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2902 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2903 wl->scan.req = NULL;
2904 ieee80211_scan_completed(wl->hw, true);
2905
2906out_sleep:
2907 wl1271_ps_elp_sleep(wl);
2908out:
2909 mutex_unlock(&wl->mutex);
2910
2911 cancel_delayed_work_sync(&wl->scan_complete_work);
2912}
2913
Luciano Coelho33c2c062011-05-10 14:46:02 +03002914static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2915 struct ieee80211_vif *vif,
2916 struct cfg80211_sched_scan_request *req,
2917 struct ieee80211_sched_scan_ies *ies)
2918{
2919 struct wl1271 *wl = hw->priv;
2920 int ret;
2921
2922 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2923
2924 mutex_lock(&wl->mutex);
2925
2926 ret = wl1271_ps_elp_wakeup(wl);
2927 if (ret < 0)
2928 goto out;
2929
2930 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2931 if (ret < 0)
2932 goto out_sleep;
2933
2934 ret = wl1271_scan_sched_scan_start(wl);
2935 if (ret < 0)
2936 goto out_sleep;
2937
2938 wl->sched_scanning = true;
2939
2940out_sleep:
2941 wl1271_ps_elp_sleep(wl);
2942out:
2943 mutex_unlock(&wl->mutex);
2944 return ret;
2945}
2946
2947static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2948 struct ieee80211_vif *vif)
2949{
2950 struct wl1271 *wl = hw->priv;
2951 int ret;
2952
2953 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2954
2955 mutex_lock(&wl->mutex);
2956
2957 ret = wl1271_ps_elp_wakeup(wl);
2958 if (ret < 0)
2959 goto out;
2960
2961 wl1271_scan_sched_scan_stop(wl);
2962
2963 wl1271_ps_elp_sleep(wl);
2964out:
2965 mutex_unlock(&wl->mutex);
2966}
2967
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002968static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2969{
2970 struct wl1271 *wl = hw->priv;
2971 int ret = 0;
2972
2973 mutex_lock(&wl->mutex);
2974
2975 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2976 ret = -EAGAIN;
2977 goto out;
2978 }
2979
Ido Yariva6208652011-03-01 15:14:41 +02002980 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002981 if (ret < 0)
2982 goto out;
2983
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002984 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002985 if (ret < 0)
2986 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2987
2988 wl1271_ps_elp_sleep(wl);
2989
2990out:
2991 mutex_unlock(&wl->mutex);
2992
2993 return ret;
2994}
2995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2997{
2998 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002999 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000
3001 mutex_lock(&wl->mutex);
3002
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003003 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3004 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003005 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003006 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003007
Ido Yariva6208652011-03-01 15:14:41 +02003008 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 if (ret < 0)
3010 goto out;
3011
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003012 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003013 if (ret < 0)
3014 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3015
3016 wl1271_ps_elp_sleep(wl);
3017
3018out:
3019 mutex_unlock(&wl->mutex);
3020
3021 return ret;
3022}
3023
Arik Nemtsove78a2872010-10-16 19:07:21 +02003024static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003025 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003026{
Eliad Peller889cb362011-05-01 09:56:45 +03003027 u8 ssid_len;
3028 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3029 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003030
Eliad Peller889cb362011-05-01 09:56:45 +03003031 if (!ptr) {
3032 wl1271_error("No SSID in IEs!");
3033 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003034 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003035
Eliad Peller889cb362011-05-01 09:56:45 +03003036 ssid_len = ptr[1];
3037 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3038 wl1271_error("SSID is too long!");
3039 return -EINVAL;
3040 }
3041
3042 wl->ssid_len = ssid_len;
3043 memcpy(wl->ssid, ptr+2, ssid_len);
3044 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003045}
3046
Arik Nemtsove78a2872010-10-16 19:07:21 +02003047static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3048 struct ieee80211_bss_conf *bss_conf,
3049 u32 changed)
3050{
3051 int ret = 0;
3052
3053 if (changed & BSS_CHANGED_ERP_SLOT) {
3054 if (bss_conf->use_short_slot)
3055 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3056 else
3057 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3058 if (ret < 0) {
3059 wl1271_warning("Set slot time failed %d", ret);
3060 goto out;
3061 }
3062 }
3063
3064 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3065 if (bss_conf->use_short_preamble)
3066 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3067 else
3068 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3069 }
3070
3071 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3072 if (bss_conf->use_cts_prot)
3073 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3074 else
3075 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3076 if (ret < 0) {
3077 wl1271_warning("Set ctsprotect failed %d", ret);
3078 goto out;
3079 }
3080 }
3081
3082out:
3083 return ret;
3084}
3085
3086static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3087 struct ieee80211_vif *vif,
3088 struct ieee80211_bss_conf *bss_conf,
3089 u32 changed)
3090{
3091 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3092 int ret = 0;
3093
3094 if ((changed & BSS_CHANGED_BEACON_INT)) {
3095 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3096 bss_conf->beacon_int);
3097
3098 wl->beacon_int = bss_conf->beacon_int;
3099 }
3100
3101 if ((changed & BSS_CHANGED_BEACON)) {
3102 struct ieee80211_hdr *hdr;
3103 int ieoffset = offsetof(struct ieee80211_mgmt,
3104 u.beacon.variable);
3105 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3106 u16 tmpl_id;
3107
3108 if (!beacon)
3109 goto out;
3110
3111 wl1271_debug(DEBUG_MASTER, "beacon updated");
3112
3113 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3114 if (ret < 0) {
3115 dev_kfree_skb(beacon);
3116 goto out;
3117 }
3118 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3119 CMD_TEMPL_BEACON;
3120 ret = wl1271_cmd_template_set(wl, tmpl_id,
3121 beacon->data,
3122 beacon->len, 0,
3123 wl1271_tx_min_rate_get(wl));
3124 if (ret < 0) {
3125 dev_kfree_skb(beacon);
3126 goto out;
3127 }
3128
3129 hdr = (struct ieee80211_hdr *) beacon->data;
3130 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3131 IEEE80211_STYPE_PROBE_RESP);
3132
3133 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3134 CMD_TEMPL_PROBE_RESPONSE;
3135 ret = wl1271_cmd_template_set(wl,
3136 tmpl_id,
3137 beacon->data,
3138 beacon->len, 0,
3139 wl1271_tx_min_rate_get(wl));
3140 dev_kfree_skb(beacon);
3141 if (ret < 0)
3142 goto out;
3143 }
3144
3145out:
3146 return ret;
3147}
3148
3149/* AP mode changes */
3150static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003151 struct ieee80211_vif *vif,
3152 struct ieee80211_bss_conf *bss_conf,
3153 u32 changed)
3154{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003155 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156
Arik Nemtsove78a2872010-10-16 19:07:21 +02003157 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3158 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159
Arik Nemtsove78a2872010-10-16 19:07:21 +02003160 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3161 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162
Arik Nemtsov70f47422011-04-18 14:15:25 +03003163 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003164 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003165 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003166 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003167 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003168
3169 ret = wl1271_ap_init_templates(wl);
3170 if (ret < 0)
3171 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003172 }
3173
Arik Nemtsove78a2872010-10-16 19:07:21 +02003174 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3175 if (ret < 0)
3176 goto out;
3177
3178 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3179 if (bss_conf->enable_beacon) {
3180 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003181 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003182 if (ret < 0)
3183 goto out;
3184
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003185 ret = wl1271_ap_init_hwenc(wl);
3186 if (ret < 0)
3187 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003188
3189 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3190 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003191 }
3192 } else {
3193 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003194 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003195 if (ret < 0)
3196 goto out;
3197
3198 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3199 wl1271_debug(DEBUG_AP, "stopped AP");
3200 }
3201 }
3202 }
3203
3204 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3205 if (ret < 0)
3206 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003207
3208 /* Handle HT information change */
3209 if ((changed & BSS_CHANGED_HT) &&
3210 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3211 ret = wl1271_acx_set_ht_information(wl,
3212 bss_conf->ht_operation_mode);
3213 if (ret < 0) {
3214 wl1271_warning("Set ht information failed %d", ret);
3215 goto out;
3216 }
3217 }
3218
Arik Nemtsove78a2872010-10-16 19:07:21 +02003219out:
3220 return;
3221}
3222
3223/* STA/IBSS mode changes */
3224static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3225 struct ieee80211_vif *vif,
3226 struct ieee80211_bss_conf *bss_conf,
3227 u32 changed)
3228{
3229 bool do_join = false, set_assoc = false;
3230 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003231 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003232 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003233 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003234 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003235 bool sta_exists = false;
3236 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003237
3238 if (is_ibss) {
3239 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3240 changed);
3241 if (ret < 0)
3242 goto out;
3243 }
3244
Eliad Peller227e81e2011-08-14 13:17:26 +03003245 if (changed & BSS_CHANGED_IBSS) {
3246 if (bss_conf->ibss_joined) {
3247 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3248 ibss_joined = true;
3249 } else {
3250 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3251 &wl->flags)) {
3252 wl1271_unjoin(wl);
3253 wl12xx_cmd_role_start_dev(wl);
3254 wl12xx_roc(wl, wl->dev_role_id);
3255 }
3256 }
3257 }
3258
3259 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003260 do_join = true;
3261
3262 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003263 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003264 do_join = true;
3265
Eliad Peller227e81e2011-08-14 13:17:26 +03003266 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003267 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3268 bss_conf->enable_beacon ? "enabled" : "disabled");
3269
3270 if (bss_conf->enable_beacon)
3271 wl->set_bss_type = BSS_TYPE_IBSS;
3272 else
3273 wl->set_bss_type = BSS_TYPE_STA_BSS;
3274 do_join = true;
3275 }
3276
Arik Nemtsove78a2872010-10-16 19:07:21 +02003277 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003278 bool enable = false;
3279 if (bss_conf->cqm_rssi_thold)
3280 enable = true;
3281 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3282 bss_conf->cqm_rssi_thold,
3283 bss_conf->cqm_rssi_hyst);
3284 if (ret < 0)
3285 goto out;
3286 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3287 }
3288
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003289 if ((changed & BSS_CHANGED_BSSID) &&
3290 /*
3291 * Now we know the correct bssid, so we send a new join command
3292 * and enable the BSSID filter
3293 */
3294 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003295 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003296
Eliad Pellerfa287b82010-12-26 09:27:50 +01003297 if (!is_zero_ether_addr(wl->bssid)) {
3298 ret = wl1271_cmd_build_null_data(wl);
3299 if (ret < 0)
3300 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003301
Eliad Pellerfa287b82010-12-26 09:27:50 +01003302 ret = wl1271_build_qos_null_data(wl);
3303 if (ret < 0)
3304 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003305
Eliad Pellerfa287b82010-12-26 09:27:50 +01003306 /* Need to update the BSSID (for filtering etc) */
3307 do_join = true;
3308 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003309 }
3310
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003311 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3312 rcu_read_lock();
3313 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3314 if (!sta)
3315 goto sta_not_found;
3316
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003317 /* save the supp_rates of the ap */
3318 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3319 if (sta->ht_cap.ht_supported)
3320 sta_rate_set |=
3321 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003322 sta_ht_cap = sta->ht_cap;
3323 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003324
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003325sta_not_found:
3326 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003327 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003328
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003330 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003331 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003332 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003333 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003334 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003335
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003336 wl->ps_poll_failures = 0;
3337
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003338 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003339 * use basic rates from AP, and determine lowest rate
3340 * to use with control frames.
3341 */
3342 rates = bss_conf->basic_rates;
3343 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3344 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003345 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003346 if (sta_rate_set)
3347 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3348 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003349 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003350 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003351 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003352
3353 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003354 * with wl1271, we don't need to update the
3355 * beacon_int and dtim_period, because the firmware
3356 * updates it by itself when the first beacon is
3357 * received after a join.
3358 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3360 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003361 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003362
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003363 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003364 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003365 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003366 dev_kfree_skb(wl->probereq);
3367 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3368 ieoffset = offsetof(struct ieee80211_mgmt,
3369 u.probe_req.variable);
3370 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003371
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003372 /* enable the connection monitoring feature */
3373 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003374 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003376 } else {
3377 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003378 bool was_assoc =
3379 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3380 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003381 bool was_ifup =
3382 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3383 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003384 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003385
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003386 /* free probe-request template */
3387 dev_kfree_skb(wl->probereq);
3388 wl->probereq = NULL;
3389
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003390 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003391 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003392
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003393 /* revert back to minimum rates for the current band */
3394 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003395 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003396 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003397 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003399
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003400 /* disable connection monitor features */
3401 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003402
3403 /* Disable the keep-alive feature */
3404 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003405 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003406 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003407
3408 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003409 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003410 u32 conf_flags = wl->hw->conf.flags;
3411 /*
3412 * we might have to disable roc, if there was
3413 * no IF_OPER_UP notification.
3414 */
3415 if (!was_ifup) {
3416 ret = wl12xx_croc(wl, wl->role_id);
3417 if (ret < 0)
3418 goto out;
3419 }
3420 /*
3421 * (we also need to disable roc in case of
3422 * roaming on the same channel. until we will
3423 * have a better flow...)
3424 */
3425 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3426 ret = wl12xx_croc(wl, wl->dev_role_id);
3427 if (ret < 0)
3428 goto out;
3429 }
3430
Eliad Peller30df14d2011-04-05 19:13:28 +03003431 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003432 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3433 wl12xx_cmd_role_start_dev(wl);
3434 wl12xx_roc(wl, wl->dev_role_id);
3435 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003436 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003437 }
3438 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003439
Eliad Pellerd192d262011-05-24 14:33:08 +03003440 if (changed & BSS_CHANGED_IBSS) {
3441 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3442 bss_conf->ibss_joined);
3443
3444 if (bss_conf->ibss_joined) {
3445 u32 rates = bss_conf->basic_rates;
3446 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3447 rates);
3448 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3449
3450 /* by default, use 11b rates */
3451 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3452 ret = wl1271_acx_sta_rate_policies(wl);
3453 if (ret < 0)
3454 goto out;
3455 }
3456 }
3457
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3459 if (ret < 0)
3460 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003462 if (changed & BSS_CHANGED_ARP_FILTER) {
3463 __be32 addr = bss_conf->arp_addr_list[0];
3464 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3465
Eliad Pellerc5312772010-12-09 11:31:27 +02003466 if (bss_conf->arp_addr_cnt == 1 &&
3467 bss_conf->arp_filter_enabled) {
3468 /*
3469 * The template should have been configured only upon
3470 * association. however, it seems that the correct ip
3471 * isn't being set (when sending), so we have to
3472 * reconfigure the template upon every ip change.
3473 */
3474 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3475 if (ret < 0) {
3476 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003477 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003478 }
3479
3480 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003481 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003482 addr);
3483 } else
3484 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003485
3486 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003487 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003488 }
3489
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003490 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003491 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003492 if (ret < 0) {
3493 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003494 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003495 }
Eliad Peller251c1772011-08-14 13:17:17 +03003496
3497 /* ROC until connected (after EAPOL exchange) */
3498 if (!is_ibss) {
3499 ret = wl12xx_roc(wl, wl->role_id);
3500 if (ret < 0)
3501 goto out;
3502
3503 wl1271_check_operstate(wl,
3504 ieee80211_get_operstate(vif));
3505 }
3506 /*
3507 * stop device role if started (we might already be in
3508 * STA role). TODO: make it better.
3509 */
3510 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3511 ret = wl12xx_croc(wl, wl->dev_role_id);
3512 if (ret < 0)
3513 goto out;
3514
3515 ret = wl12xx_cmd_role_stop_dev(wl);
3516 if (ret < 0)
3517 goto out;
3518 }
Eliad Peller05dba352011-08-23 16:37:01 +03003519
3520 /* If we want to go in PSM but we're not there yet */
3521 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3522 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3523 enum wl1271_cmd_ps_mode mode;
3524
3525 mode = STATION_POWER_SAVE_MODE;
3526 ret = wl1271_ps_set_mode(wl, mode,
3527 wl->basic_rate,
3528 true);
3529 if (ret < 0)
3530 goto out;
3531 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003532 }
3533
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003534 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003535 if (sta_exists) {
3536 if ((changed & BSS_CHANGED_HT) &&
3537 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003538 ret = wl1271_acx_set_ht_capabilities(wl,
3539 &sta_ht_cap,
3540 true,
3541 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003542 if (ret < 0) {
3543 wl1271_warning("Set ht cap true failed %d",
3544 ret);
3545 goto out;
3546 }
3547 }
3548 /* handle new association without HT and disassociation */
3549 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003550 ret = wl1271_acx_set_ht_capabilities(wl,
3551 &sta_ht_cap,
3552 false,
3553 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003554 if (ret < 0) {
3555 wl1271_warning("Set ht cap false failed %d",
3556 ret);
3557 goto out;
3558 }
3559 }
3560 }
3561
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003562 /* Handle HT information change. Done after join. */
3563 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003564 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3565 ret = wl1271_acx_set_ht_information(wl,
3566 bss_conf->ht_operation_mode);
3567 if (ret < 0) {
3568 wl1271_warning("Set ht information failed %d", ret);
3569 goto out;
3570 }
3571 }
3572
Arik Nemtsove78a2872010-10-16 19:07:21 +02003573out:
3574 return;
3575}
3576
3577static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3578 struct ieee80211_vif *vif,
3579 struct ieee80211_bss_conf *bss_conf,
3580 u32 changed)
3581{
3582 struct wl1271 *wl = hw->priv;
3583 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3584 int ret;
3585
3586 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3587 (int)changed);
3588
3589 mutex_lock(&wl->mutex);
3590
3591 if (unlikely(wl->state == WL1271_STATE_OFF))
3592 goto out;
3593
Ido Yariva6208652011-03-01 15:14:41 +02003594 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003595 if (ret < 0)
3596 goto out;
3597
3598 if (is_ap)
3599 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3600 else
3601 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3602
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003603 wl1271_ps_elp_sleep(wl);
3604
3605out:
3606 mutex_unlock(&wl->mutex);
3607}
3608
Kalle Valoc6999d82010-02-18 13:25:41 +02003609static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3610 const struct ieee80211_tx_queue_params *params)
3611{
3612 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003613 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003614 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003615
3616 mutex_lock(&wl->mutex);
3617
3618 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3619
Kalle Valo4695dc92010-03-18 12:26:38 +02003620 if (params->uapsd)
3621 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3622 else
3623 ps_scheme = CONF_PS_SCHEME_LEGACY;
3624
Arik Nemtsov488fc542010-10-16 20:33:45 +02003625 if (wl->state == WL1271_STATE_OFF) {
3626 /*
3627 * If the state is off, the parameters will be recorded and
3628 * configured on init. This happens in AP-mode.
3629 */
3630 struct conf_tx_ac_category *conf_ac =
3631 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3632 struct conf_tx_tid *conf_tid =
3633 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3634
3635 conf_ac->ac = wl1271_tx_get_queue(queue);
3636 conf_ac->cw_min = (u8)params->cw_min;
3637 conf_ac->cw_max = params->cw_max;
3638 conf_ac->aifsn = params->aifs;
3639 conf_ac->tx_op_limit = params->txop << 5;
3640
3641 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3642 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3643 conf_tid->tsid = wl1271_tx_get_queue(queue);
3644 conf_tid->ps_scheme = ps_scheme;
3645 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3646 conf_tid->apsd_conf[0] = 0;
3647 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003648 goto out;
3649 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003650
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003651 ret = wl1271_ps_elp_wakeup(wl);
3652 if (ret < 0)
3653 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003654
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003655 /*
3656 * the txop is confed in units of 32us by the mac80211,
3657 * we need us
3658 */
3659 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3660 params->cw_min, params->cw_max,
3661 params->aifs, params->txop << 5);
3662 if (ret < 0)
3663 goto out_sleep;
3664
3665 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3666 CONF_CHANNEL_TYPE_EDCF,
3667 wl1271_tx_get_queue(queue),
3668 ps_scheme, CONF_ACK_POLICY_LEGACY,
3669 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003670
3671out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003672 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003673
3674out:
3675 mutex_unlock(&wl->mutex);
3676
3677 return ret;
3678}
3679
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003680static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3681{
3682
3683 struct wl1271 *wl = hw->priv;
3684 u64 mactime = ULLONG_MAX;
3685 int ret;
3686
3687 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3688
3689 mutex_lock(&wl->mutex);
3690
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003691 if (unlikely(wl->state == WL1271_STATE_OFF))
3692 goto out;
3693
Ido Yariva6208652011-03-01 15:14:41 +02003694 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003695 if (ret < 0)
3696 goto out;
3697
3698 ret = wl1271_acx_tsf_info(wl, &mactime);
3699 if (ret < 0)
3700 goto out_sleep;
3701
3702out_sleep:
3703 wl1271_ps_elp_sleep(wl);
3704
3705out:
3706 mutex_unlock(&wl->mutex);
3707 return mactime;
3708}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003709
John W. Linvilleece550d2010-07-28 16:41:06 -04003710static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3711 struct survey_info *survey)
3712{
3713 struct wl1271 *wl = hw->priv;
3714 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003715
John W. Linvilleece550d2010-07-28 16:41:06 -04003716 if (idx != 0)
3717 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003718
John W. Linvilleece550d2010-07-28 16:41:06 -04003719 survey->channel = conf->channel;
3720 survey->filled = SURVEY_INFO_NOISE_DBM;
3721 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003722
John W. Linvilleece550d2010-07-28 16:41:06 -04003723 return 0;
3724}
3725
Arik Nemtsov409622e2011-02-23 00:22:29 +02003726static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003727 struct ieee80211_sta *sta,
3728 u8 *hlid)
3729{
3730 struct wl1271_station *wl_sta;
3731 int id;
3732
3733 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3734 if (id >= AP_MAX_STATIONS) {
3735 wl1271_warning("could not allocate HLID - too much stations");
3736 return -EBUSY;
3737 }
3738
3739 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003740 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003741 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3742 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003743 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003744 return 0;
3745}
3746
Arik Nemtsov409622e2011-02-23 00:22:29 +02003747static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003748{
3749 int id = hlid - WL1271_AP_STA_HLID_START;
3750
Arik Nemtsov409622e2011-02-23 00:22:29 +02003751 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3752 return;
3753
Arik Nemtsov04216da2011-08-14 13:17:38 +03003754 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003755 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003756 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003757 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003758 __clear_bit(hlid, &wl->ap_ps_map);
3759 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003760}
3761
3762static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3763 struct ieee80211_vif *vif,
3764 struct ieee80211_sta *sta)
3765{
3766 struct wl1271 *wl = hw->priv;
3767 int ret = 0;
3768 u8 hlid;
3769
3770 mutex_lock(&wl->mutex);
3771
3772 if (unlikely(wl->state == WL1271_STATE_OFF))
3773 goto out;
3774
3775 if (wl->bss_type != BSS_TYPE_AP_BSS)
3776 goto out;
3777
3778 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3779
Arik Nemtsov409622e2011-02-23 00:22:29 +02003780 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003781 if (ret < 0)
3782 goto out;
3783
Ido Yariva6208652011-03-01 15:14:41 +02003784 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003785 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003786 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003787
Eliad Pellerc690ec82011-08-14 13:17:07 +03003788 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003789 if (ret < 0)
3790 goto out_sleep;
3791
Eliad Pellerb67476e2011-08-14 13:17:23 +03003792 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3793 if (ret < 0)
3794 goto out_sleep;
3795
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003796 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3797 if (ret < 0)
3798 goto out_sleep;
3799
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003800out_sleep:
3801 wl1271_ps_elp_sleep(wl);
3802
Arik Nemtsov409622e2011-02-23 00:22:29 +02003803out_free_sta:
3804 if (ret < 0)
3805 wl1271_free_sta(wl, hlid);
3806
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003807out:
3808 mutex_unlock(&wl->mutex);
3809 return ret;
3810}
3811
3812static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3813 struct ieee80211_vif *vif,
3814 struct ieee80211_sta *sta)
3815{
3816 struct wl1271 *wl = hw->priv;
3817 struct wl1271_station *wl_sta;
3818 int ret = 0, id;
3819
3820 mutex_lock(&wl->mutex);
3821
3822 if (unlikely(wl->state == WL1271_STATE_OFF))
3823 goto out;
3824
3825 if (wl->bss_type != BSS_TYPE_AP_BSS)
3826 goto out;
3827
3828 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3829
3830 wl_sta = (struct wl1271_station *)sta->drv_priv;
3831 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3832 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3833 goto out;
3834
Ido Yariva6208652011-03-01 15:14:41 +02003835 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003836 if (ret < 0)
3837 goto out;
3838
Eliad Pellerc690ec82011-08-14 13:17:07 +03003839 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003840 if (ret < 0)
3841 goto out_sleep;
3842
Arik Nemtsov409622e2011-02-23 00:22:29 +02003843 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003844
3845out_sleep:
3846 wl1271_ps_elp_sleep(wl);
3847
3848out:
3849 mutex_unlock(&wl->mutex);
3850 return ret;
3851}
3852
Luciano Coelho4623ec72011-03-21 19:26:41 +02003853static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3854 struct ieee80211_vif *vif,
3855 enum ieee80211_ampdu_mlme_action action,
3856 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3857 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003858{
3859 struct wl1271 *wl = hw->priv;
3860 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003861 u8 hlid, *ba_bitmap;
3862
3863 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3864 tid);
3865
3866 /* sanity check - the fields in FW are only 8bits wide */
3867 if (WARN_ON(tid > 0xFF))
3868 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003869
3870 mutex_lock(&wl->mutex);
3871
3872 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3873 ret = -EAGAIN;
3874 goto out;
3875 }
3876
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003877 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3878 hlid = wl->sta_hlid;
3879 ba_bitmap = &wl->ba_rx_bitmap;
3880 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3881 struct wl1271_station *wl_sta;
3882
3883 wl_sta = (struct wl1271_station *)sta->drv_priv;
3884 hlid = wl_sta->hlid;
3885 ba_bitmap = &wl->links[hlid].ba_bitmap;
3886 } else {
3887 ret = -EINVAL;
3888 goto out;
3889 }
3890
Ido Yariva6208652011-03-01 15:14:41 +02003891 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003892 if (ret < 0)
3893 goto out;
3894
Shahar Levi70559a02011-05-22 16:10:22 +03003895 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3896 tid, action);
3897
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003898 switch (action) {
3899 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003900 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003901 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003902 break;
3903 }
3904
3905 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3906 ret = -EBUSY;
3907 wl1271_error("exceeded max RX BA sessions");
3908 break;
3909 }
3910
3911 if (*ba_bitmap & BIT(tid)) {
3912 ret = -EINVAL;
3913 wl1271_error("cannot enable RX BA session on active "
3914 "tid: %d", tid);
3915 break;
3916 }
3917
3918 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3919 hlid);
3920 if (!ret) {
3921 *ba_bitmap |= BIT(tid);
3922 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003923 }
3924 break;
3925
3926 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003927 if (!(*ba_bitmap & BIT(tid))) {
3928 ret = -EINVAL;
3929 wl1271_error("no active RX BA session on tid: %d",
3930 tid);
3931 break;
3932 }
3933
3934 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3935 hlid);
3936 if (!ret) {
3937 *ba_bitmap &= ~BIT(tid);
3938 wl->ba_rx_session_count--;
3939 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003940 break;
3941
3942 /*
3943 * The BA initiator session management in FW independently.
3944 * Falling break here on purpose for all TX APDU commands.
3945 */
3946 case IEEE80211_AMPDU_TX_START:
3947 case IEEE80211_AMPDU_TX_STOP:
3948 case IEEE80211_AMPDU_TX_OPERATIONAL:
3949 ret = -EINVAL;
3950 break;
3951
3952 default:
3953 wl1271_error("Incorrect ampdu action id=%x\n", action);
3954 ret = -EINVAL;
3955 }
3956
3957 wl1271_ps_elp_sleep(wl);
3958
3959out:
3960 mutex_unlock(&wl->mutex);
3961
3962 return ret;
3963}
3964
Arik Nemtsov33437892011-04-26 23:35:39 +03003965static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3966{
3967 struct wl1271 *wl = hw->priv;
3968 bool ret = false;
3969
3970 mutex_lock(&wl->mutex);
3971
3972 if (unlikely(wl->state == WL1271_STATE_OFF))
3973 goto out;
3974
3975 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003976 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003977
3978 /* the above is appropriate for STA mode for PS purposes */
3979 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3980
3981out:
3982 mutex_unlock(&wl->mutex);
3983
3984 return ret;
3985}
3986
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003987/* can't be const, mac80211 writes to this */
3988static struct ieee80211_rate wl1271_rates[] = {
3989 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003990 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3991 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003992 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003993 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3994 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003995 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3996 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003997 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3998 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003999 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4000 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004001 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4002 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004003 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4004 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004005 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4006 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004007 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004008 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4009 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004010 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004011 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4012 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004013 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004014 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4015 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004016 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004017 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4018 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004019 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004020 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4021 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004022 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004023 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4024 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004025 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004026 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4027 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004028};
4029
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004030/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004031static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004032 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004033 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004034 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4035 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4036 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004037 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004038 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4039 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4040 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004041 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004042 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4043 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4044 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004045 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004046};
4047
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004048/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004049static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004050 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004051 7, /* CONF_HW_RXTX_RATE_MCS7 */
4052 6, /* CONF_HW_RXTX_RATE_MCS6 */
4053 5, /* CONF_HW_RXTX_RATE_MCS5 */
4054 4, /* CONF_HW_RXTX_RATE_MCS4 */
4055 3, /* CONF_HW_RXTX_RATE_MCS3 */
4056 2, /* CONF_HW_RXTX_RATE_MCS2 */
4057 1, /* CONF_HW_RXTX_RATE_MCS1 */
4058 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004059
4060 11, /* CONF_HW_RXTX_RATE_54 */
4061 10, /* CONF_HW_RXTX_RATE_48 */
4062 9, /* CONF_HW_RXTX_RATE_36 */
4063 8, /* CONF_HW_RXTX_RATE_24 */
4064
4065 /* TI-specific rate */
4066 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4067
4068 7, /* CONF_HW_RXTX_RATE_18 */
4069 6, /* CONF_HW_RXTX_RATE_12 */
4070 3, /* CONF_HW_RXTX_RATE_11 */
4071 5, /* CONF_HW_RXTX_RATE_9 */
4072 4, /* CONF_HW_RXTX_RATE_6 */
4073 2, /* CONF_HW_RXTX_RATE_5_5 */
4074 1, /* CONF_HW_RXTX_RATE_2 */
4075 0 /* CONF_HW_RXTX_RATE_1 */
4076};
4077
Shahar Levie8b03a22010-10-13 16:09:39 +02004078/* 11n STA capabilities */
4079#define HW_RX_HIGHEST_RATE 72
4080
Shahar Levi00d20102010-11-08 11:20:10 +00004081#ifdef CONFIG_WL12XX_HT
4082#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004083 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4084 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004085 .ht_supported = true, \
4086 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4087 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4088 .mcs = { \
4089 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4090 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4091 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4092 }, \
4093}
Shahar Levi18357852010-10-13 16:09:41 +02004094#else
Shahar Levi00d20102010-11-08 11:20:10 +00004095#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004096 .ht_supported = false, \
4097}
4098#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004100/* can't be const, mac80211 writes to this */
4101static struct ieee80211_supported_band wl1271_band_2ghz = {
4102 .channels = wl1271_channels,
4103 .n_channels = ARRAY_SIZE(wl1271_channels),
4104 .bitrates = wl1271_rates,
4105 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004106 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004107};
4108
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004109/* 5 GHz data rates for WL1273 */
4110static struct ieee80211_rate wl1271_rates_5ghz[] = {
4111 { .bitrate = 60,
4112 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4113 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4114 { .bitrate = 90,
4115 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4116 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4117 { .bitrate = 120,
4118 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4119 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4120 { .bitrate = 180,
4121 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4122 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4123 { .bitrate = 240,
4124 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4125 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4126 { .bitrate = 360,
4127 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4128 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4129 { .bitrate = 480,
4130 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4131 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4132 { .bitrate = 540,
4133 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4134 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4135};
4136
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004137/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004138static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004139 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4140 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4141 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4142 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4143 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4144 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4145 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4146 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4147 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4148 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4149 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4150 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4151 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4152 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4153 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4154 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4155 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4156 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4157 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4158 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4159 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4160 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4161 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4162 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4163 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4164 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4165 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4166 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4167 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4168 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4169 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4170 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4171 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4172 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004173};
4174
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004175/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004176static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004177 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004178 7, /* CONF_HW_RXTX_RATE_MCS7 */
4179 6, /* CONF_HW_RXTX_RATE_MCS6 */
4180 5, /* CONF_HW_RXTX_RATE_MCS5 */
4181 4, /* CONF_HW_RXTX_RATE_MCS4 */
4182 3, /* CONF_HW_RXTX_RATE_MCS3 */
4183 2, /* CONF_HW_RXTX_RATE_MCS2 */
4184 1, /* CONF_HW_RXTX_RATE_MCS1 */
4185 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004186
4187 7, /* CONF_HW_RXTX_RATE_54 */
4188 6, /* CONF_HW_RXTX_RATE_48 */
4189 5, /* CONF_HW_RXTX_RATE_36 */
4190 4, /* CONF_HW_RXTX_RATE_24 */
4191
4192 /* TI-specific rate */
4193 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4194
4195 3, /* CONF_HW_RXTX_RATE_18 */
4196 2, /* CONF_HW_RXTX_RATE_12 */
4197 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4198 1, /* CONF_HW_RXTX_RATE_9 */
4199 0, /* CONF_HW_RXTX_RATE_6 */
4200 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4201 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4202 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4203};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004204
4205static struct ieee80211_supported_band wl1271_band_5ghz = {
4206 .channels = wl1271_channels_5ghz,
4207 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4208 .bitrates = wl1271_rates_5ghz,
4209 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004210 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004211};
4212
Tobias Klausera0ea9492010-05-20 10:38:11 +02004213static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004214 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4215 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4216};
4217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004218static const struct ieee80211_ops wl1271_ops = {
4219 .start = wl1271_op_start,
4220 .stop = wl1271_op_stop,
4221 .add_interface = wl1271_op_add_interface,
4222 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004223#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004224 .suspend = wl1271_op_suspend,
4225 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004226#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004227 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004228 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004229 .configure_filter = wl1271_op_configure_filter,
4230 .tx = wl1271_op_tx,
4231 .set_key = wl1271_op_set_key,
4232 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004233 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004234 .sched_scan_start = wl1271_op_sched_scan_start,
4235 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004236 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004237 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004238 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004239 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004240 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004241 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004242 .sta_add = wl1271_op_sta_add,
4243 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004245 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004246 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004247};
4248
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004249
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004250u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004251{
4252 u8 idx;
4253
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004254 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004255
4256 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4257 wl1271_error("Illegal RX rate from HW: %d", rate);
4258 return 0;
4259 }
4260
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004261 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004262 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4263 wl1271_error("Unsupported RX rate from HW: %d", rate);
4264 return 0;
4265 }
4266
4267 return idx;
4268}
4269
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004270static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4271 struct device_attribute *attr,
4272 char *buf)
4273{
4274 struct wl1271 *wl = dev_get_drvdata(dev);
4275 ssize_t len;
4276
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004277 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004278
4279 mutex_lock(&wl->mutex);
4280 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4281 wl->sg_enabled);
4282 mutex_unlock(&wl->mutex);
4283
4284 return len;
4285
4286}
4287
4288static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4289 struct device_attribute *attr,
4290 const char *buf, size_t count)
4291{
4292 struct wl1271 *wl = dev_get_drvdata(dev);
4293 unsigned long res;
4294 int ret;
4295
Luciano Coelho6277ed62011-04-01 17:49:54 +03004296 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004297 if (ret < 0) {
4298 wl1271_warning("incorrect value written to bt_coex_mode");
4299 return count;
4300 }
4301
4302 mutex_lock(&wl->mutex);
4303
4304 res = !!res;
4305
4306 if (res == wl->sg_enabled)
4307 goto out;
4308
4309 wl->sg_enabled = res;
4310
4311 if (wl->state == WL1271_STATE_OFF)
4312 goto out;
4313
Ido Yariva6208652011-03-01 15:14:41 +02004314 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004315 if (ret < 0)
4316 goto out;
4317
4318 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4319 wl1271_ps_elp_sleep(wl);
4320
4321 out:
4322 mutex_unlock(&wl->mutex);
4323 return count;
4324}
4325
4326static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4327 wl1271_sysfs_show_bt_coex_state,
4328 wl1271_sysfs_store_bt_coex_state);
4329
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004330static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4331 struct device_attribute *attr,
4332 char *buf)
4333{
4334 struct wl1271 *wl = dev_get_drvdata(dev);
4335 ssize_t len;
4336
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004337 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004338
4339 mutex_lock(&wl->mutex);
4340 if (wl->hw_pg_ver >= 0)
4341 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4342 else
4343 len = snprintf(buf, len, "n/a\n");
4344 mutex_unlock(&wl->mutex);
4345
4346 return len;
4347}
4348
Gery Kahn6f07b722011-07-18 14:21:49 +03004349static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004350 wl1271_sysfs_show_hw_pg_ver, NULL);
4351
Ido Yariv95dac04f2011-06-06 14:57:06 +03004352static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4353 struct bin_attribute *bin_attr,
4354 char *buffer, loff_t pos, size_t count)
4355{
4356 struct device *dev = container_of(kobj, struct device, kobj);
4357 struct wl1271 *wl = dev_get_drvdata(dev);
4358 ssize_t len;
4359 int ret;
4360
4361 ret = mutex_lock_interruptible(&wl->mutex);
4362 if (ret < 0)
4363 return -ERESTARTSYS;
4364
4365 /* Let only one thread read the log at a time, blocking others */
4366 while (wl->fwlog_size == 0) {
4367 DEFINE_WAIT(wait);
4368
4369 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4370 &wait,
4371 TASK_INTERRUPTIBLE);
4372
4373 if (wl->fwlog_size != 0) {
4374 finish_wait(&wl->fwlog_waitq, &wait);
4375 break;
4376 }
4377
4378 mutex_unlock(&wl->mutex);
4379
4380 schedule();
4381 finish_wait(&wl->fwlog_waitq, &wait);
4382
4383 if (signal_pending(current))
4384 return -ERESTARTSYS;
4385
4386 ret = mutex_lock_interruptible(&wl->mutex);
4387 if (ret < 0)
4388 return -ERESTARTSYS;
4389 }
4390
4391 /* Check if the fwlog is still valid */
4392 if (wl->fwlog_size < 0) {
4393 mutex_unlock(&wl->mutex);
4394 return 0;
4395 }
4396
4397 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4398 len = min(count, (size_t)wl->fwlog_size);
4399 wl->fwlog_size -= len;
4400 memcpy(buffer, wl->fwlog, len);
4401
4402 /* Make room for new messages */
4403 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4404
4405 mutex_unlock(&wl->mutex);
4406
4407 return len;
4408}
4409
4410static struct bin_attribute fwlog_attr = {
4411 .attr = {.name = "fwlog", .mode = S_IRUSR},
4412 .read = wl1271_sysfs_read_fwlog,
4413};
4414
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004415int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416{
4417 int ret;
4418
4419 if (wl->mac80211_registered)
4420 return 0;
4421
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004422 ret = wl1271_fetch_nvs(wl);
4423 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004424 /* NOTE: The wl->nvs->nvs element must be first, in
4425 * order to simplify the casting, we assume it is at
4426 * the beginning of the wl->nvs structure.
4427 */
4428 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004429
4430 wl->mac_addr[0] = nvs_ptr[11];
4431 wl->mac_addr[1] = nvs_ptr[10];
4432 wl->mac_addr[2] = nvs_ptr[6];
4433 wl->mac_addr[3] = nvs_ptr[5];
4434 wl->mac_addr[4] = nvs_ptr[4];
4435 wl->mac_addr[5] = nvs_ptr[3];
4436 }
4437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4439
4440 ret = ieee80211_register_hw(wl->hw);
4441 if (ret < 0) {
4442 wl1271_error("unable to register mac80211 hw: %d", ret);
4443 return ret;
4444 }
4445
4446 wl->mac80211_registered = true;
4447
Eliad Pellerd60080a2010-11-24 12:53:16 +02004448 wl1271_debugfs_init(wl);
4449
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004450 register_netdevice_notifier(&wl1271_dev_notifier);
4451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 wl1271_notice("loaded");
4453
4454 return 0;
4455}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004456EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004458void wl1271_unregister_hw(struct wl1271 *wl)
4459{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004460 if (wl->state == WL1271_STATE_PLT)
4461 __wl1271_plt_stop(wl);
4462
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004463 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004464 ieee80211_unregister_hw(wl->hw);
4465 wl->mac80211_registered = false;
4466
4467}
4468EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4469
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004470int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004472 static const u32 cipher_suites[] = {
4473 WLAN_CIPHER_SUITE_WEP40,
4474 WLAN_CIPHER_SUITE_WEP104,
4475 WLAN_CIPHER_SUITE_TKIP,
4476 WLAN_CIPHER_SUITE_CCMP,
4477 WL1271_CIPHER_SUITE_GEM,
4478 };
4479
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004480 /* The tx descriptor buffer and the TKIP space. */
4481 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4482 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004483
4484 /* unit us */
4485 /* FIXME: find a proper value */
4486 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004487 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004488
4489 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004490 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004491 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004492 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004493 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004494 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004495 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004496 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004497 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004498 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004499
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004500 wl->hw->wiphy->cipher_suites = cipher_suites;
4501 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4502
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004503 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004504 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004505 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelhof9520792011-08-23 18:34:44 +03004506 wl->hw->wiphy->max_sched_scan_ssids = 8;
Guy Eilamea559b42010-12-09 16:54:59 +02004507 /*
4508 * Maximum length of elements in scanning probe request templates
4509 * should be the maximum length possible for a template, without
4510 * the IEEE80211 header of the template
4511 */
Eliad Peller154037d2011-08-14 13:17:12 +03004512 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004513 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004514
Luciano Coelho4a31c112011-03-21 23:16:14 +02004515 /* make sure all our channels fit in the scanned_ch bitmask */
4516 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4517 ARRAY_SIZE(wl1271_channels_5ghz) >
4518 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004519 /*
4520 * We keep local copies of the band structs because we need to
4521 * modify them on a per-device basis.
4522 */
4523 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4524 sizeof(wl1271_band_2ghz));
4525 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4526 sizeof(wl1271_band_5ghz));
4527
4528 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4529 &wl->bands[IEEE80211_BAND_2GHZ];
4530 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4531 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004532
Kalle Valo12bd8942010-03-18 12:26:33 +02004533 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004534 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004535
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004536 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4537
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004538 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004540 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4541
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004542 wl->hw->max_rx_aggregation_subframes = 8;
4543
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004544 return 0;
4545}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004546EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004548#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004549
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004550struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004551{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004552 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004553 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004554 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004555 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004556 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004557
4558 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4559 if (!hw) {
4560 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004561 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004562 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004563 }
4564
Julia Lawall929ebd32010-05-15 23:16:39 +02004565 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004566 if (!plat_dev) {
4567 wl1271_error("could not allocate platform_device");
4568 ret = -ENOMEM;
4569 goto err_plat_alloc;
4570 }
4571
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004572 wl = hw->priv;
4573 memset(wl, 0, sizeof(*wl));
4574
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004575 INIT_LIST_HEAD(&wl->list);
4576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004577 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004578 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004579
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004580 for (i = 0; i < NUM_TX_QUEUES; i++)
4581 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004582
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004583 for (i = 0; i < NUM_TX_QUEUES; i++)
4584 for (j = 0; j < AP_MAX_LINKS; j++)
4585 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4586
Ido Yariva6208652011-03-01 15:14:41 +02004587 skb_queue_head_init(&wl->deferred_rx_queue);
4588 skb_queue_head_init(&wl->deferred_tx_queue);
4589
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004590 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004591 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004592 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004593 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4594 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4595 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004596 INIT_WORK(&wl->rx_streaming_enable_work,
4597 wl1271_rx_streaming_enable_work);
4598 INIT_WORK(&wl->rx_streaming_disable_work,
4599 wl1271_rx_streaming_disable_work);
4600
Eliad Peller92ef8962011-06-07 12:50:46 +03004601 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4602 if (!wl->freezable_wq) {
4603 ret = -ENOMEM;
4604 goto err_hw;
4605 }
4606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004607 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004608 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004609 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004610 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004611 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004612 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004613 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004614 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004615 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004616 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004617 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004618 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004619 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004620 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004621 wl->bss_type = MAX_BSS_TYPE;
4622 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004623 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004624 wl->ap_ps_map = 0;
4625 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004626 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004627 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004628 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004629 wl->tx_security_seq = 0;
4630 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004631 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004632 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004633 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004634 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004635 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4636 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004637 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004638 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4639 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004640 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4641 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004642 wl->fwlog_size = 0;
4643 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004644
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004645 /* The system link is always allocated */
4646 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4647
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004648 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004649 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650 wl->tx_frames[i] = NULL;
4651
4652 spin_lock_init(&wl->wl_lock);
4653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004654 wl->state = WL1271_STATE_OFF;
4655 mutex_init(&wl->mutex);
4656
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004657 /* Apply default driver configuration. */
4658 wl1271_conf_init(wl);
4659
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004660 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4661 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4662 if (!wl->aggr_buf) {
4663 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004664 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004665 }
4666
Ido Yariv990f5de2011-03-31 10:06:59 +02004667 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4668 if (!wl->dummy_packet) {
4669 ret = -ENOMEM;
4670 goto err_aggr;
4671 }
4672
Ido Yariv95dac04f2011-06-06 14:57:06 +03004673 /* Allocate one page for the FW log */
4674 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4675 if (!wl->fwlog) {
4676 ret = -ENOMEM;
4677 goto err_dummy_packet;
4678 }
4679
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004680 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004681 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004682 if (ret) {
4683 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004684 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004685 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004686 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004687
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004688 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004689 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004690 if (ret < 0) {
4691 wl1271_error("failed to create sysfs file bt_coex_state");
4692 goto err_platform;
4693 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004694
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004695 /* Create sysfs file to get HW PG version */
4696 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4697 if (ret < 0) {
4698 wl1271_error("failed to create sysfs file hw_pg_ver");
4699 goto err_bt_coex_state;
4700 }
4701
Ido Yariv95dac04f2011-06-06 14:57:06 +03004702 /* Create sysfs file for the FW log */
4703 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4704 if (ret < 0) {
4705 wl1271_error("failed to create sysfs file fwlog");
4706 goto err_hw_pg_ver;
4707 }
4708
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004709 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004710
Ido Yariv95dac04f2011-06-06 14:57:06 +03004711err_hw_pg_ver:
4712 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4713
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004714err_bt_coex_state:
4715 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4716
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004717err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004718 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004719
Ido Yariv95dac04f2011-06-06 14:57:06 +03004720err_fwlog:
4721 free_page((unsigned long)wl->fwlog);
4722
Ido Yariv990f5de2011-03-31 10:06:59 +02004723err_dummy_packet:
4724 dev_kfree_skb(wl->dummy_packet);
4725
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004726err_aggr:
4727 free_pages((unsigned long)wl->aggr_buf, order);
4728
Eliad Peller92ef8962011-06-07 12:50:46 +03004729err_wq:
4730 destroy_workqueue(wl->freezable_wq);
4731
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004732err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004733 wl1271_debugfs_exit(wl);
4734 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004735
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004736err_plat_alloc:
4737 ieee80211_free_hw(hw);
4738
4739err_hw_alloc:
4740
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004741 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004742}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004743EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004744
4745int wl1271_free_hw(struct wl1271 *wl)
4746{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004747 /* Unblock any fwlog readers */
4748 mutex_lock(&wl->mutex);
4749 wl->fwlog_size = -1;
4750 wake_up_interruptible_all(&wl->fwlog_waitq);
4751 mutex_unlock(&wl->mutex);
4752
4753 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004754
4755 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4756
4757 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004758 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004759 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004760 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004761 free_pages((unsigned long)wl->aggr_buf,
4762 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004763 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004764
4765 wl1271_debugfs_exit(wl);
4766
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004767 vfree(wl->fw);
4768 wl->fw = NULL;
4769 kfree(wl->nvs);
4770 wl->nvs = NULL;
4771
4772 kfree(wl->fw_status);
4773 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004774 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004775
4776 ieee80211_free_hw(wl->hw);
4777
4778 return 0;
4779}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004780EXPORT_SYMBOL_GPL(wl1271_free_hw);
4781
Guy Eilam491bbd62011-01-12 10:33:29 +01004782u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004783EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004784module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004785MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4786
Ido Yariv95dac04f2011-06-06 14:57:06 +03004787module_param_named(fwlog, fwlog_param, charp, 0);
4788MODULE_PARM_DESC(keymap,
4789 "FW logger options: continuous, ondemand, dbgpins or disable");
4790
Eliad Peller2a5bff02011-08-25 18:10:59 +03004791module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
4792MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
4793
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004794MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004795MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004796MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");