blob: b06ff0b25de15bfb107b64805c1ba64a18fb837d [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200239 .psm_entry_retries = 5,
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,
242 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300243 .keep_alive_interval = 55000,
244 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200246 .itrim = {
247 .enable = false,
248 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200249 },
250 .pm_config = {
251 .host_clk_settling_time = 5000,
252 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300253 },
254 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100259 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200260 },
261 .scan = {
262 .min_dwell_time_active = 7500,
263 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100264 .min_dwell_time_passive = 100000,
265 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200266 .num_probe_reqs = 2,
267 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300268 .sched_scan = {
269 /* sched_scan requires dwell times in TU instead of TU/1000 */
270 .min_dwell_time_active = 8,
271 .max_dwell_time_active = 30,
272 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300273 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300274 .num_probe_reqs = 2,
275 .rssi_threshold = -90,
276 .snr_threshold = 0,
277 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200278 .rf = {
279 .tx_per_channel_power_compensation_2 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 },
282 .tx_per_channel_power_compensation_5 = {
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 },
287 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100288 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300289 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100290 .tx_ba_win_size = 64,
291 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300292 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100293 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200294 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200295 .num_stations = 1,
296 .ssid_profiles = 1,
297 .rx_block_num = 70,
298 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300299 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200300 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .min_req_rx_blocks = 22,
302 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 },
304 .mem_wl128x = {
305 .num_stations = 1,
306 .ssid_profiles = 1,
307 .rx_block_num = 40,
308 .tx_min_block_num = 40,
309 .dynamic_memory = 1,
310 .min_req_tx_blocks = 45,
311 .min_req_rx_blocks = 22,
312 .tx_min = 27,
313 },
Shahar Leviff868432011-04-11 15:41:46 +0300314 .fm_coex = {
315 .enable = true,
316 .swallow_period = 5,
317 .n_divider_fref_set_1 = 0xff, /* default */
318 .n_divider_fref_set_2 = 12,
319 .m_divider_fref_set_1 = 148,
320 .m_divider_fref_set_2 = 0xffff, /* default */
321 .coex_pll_stabilization_time = 0xffffffff, /* default */
322 .ldo_stabilization_time = 0xffff, /* default */
323 .fm_disturbed_band_margin = 0xff, /* default */
324 .swallow_clk_diff = 0xff, /* default */
325 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300326 .rx_streaming = {
327 .duration = 150,
328 .queues = 0x1,
329 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300330 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300331 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300332 .fwlog = {
333 .mode = WL12XX_FWLOG_ON_DEMAND,
334 .mem_blocks = 2,
335 .severity = 0,
336 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
337 .output = WL12XX_FWLOG_OUTPUT_HOST,
338 .threshold = 0,
339 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300340 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300341 .rate = {
342 .rate_retry_score = 32000,
343 .per_add = 8192,
344 .per_th1 = 2048,
345 .per_th2 = 4096,
346 .max_per = 8100,
347 .inverse_curiosity_factor = 5,
348 .tx_fail_low_th = 4,
349 .tx_fail_high_th = 10,
350 .per_alpha_shift = 4,
351 .per_add_shift = 13,
352 .per_beta1_shift = 10,
353 .per_beta2_shift = 8,
354 .rate_check_up = 2,
355 .rate_check_down = 12,
356 .rate_retry_policy = {
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00,
360 },
361 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300362};
363
Ido Yariv95dac04f2011-06-06 14:57:06 +0300364static char *fwlog_param;
365
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300366static void __wl1271_op_remove_interface(struct wl1271 *wl,
367 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200368static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200369
370
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200371static void wl1271_device_release(struct device *dev)
372{
373
374}
375
376static struct platform_device wl1271_device = {
377 .name = "wl1271",
378 .id = -1,
379
380 /* device model insists to have a release function */
381 .dev = {
382 .release = wl1271_device_release,
383 },
384};
385
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200386static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300387static LIST_HEAD(wl_list);
388
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300389static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
390{
391 int ret;
392 if (operstate != IF_OPER_UP)
393 return 0;
394
395 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
396 return 0;
397
Eliad Pellerb67476e2011-08-14 13:17:23 +0300398 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 if (ret < 0)
400 return ret;
401
Eliad Peller251c1772011-08-14 13:17:17 +0300402 wl12xx_croc(wl, wl->role_id);
403
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300404 wl1271_info("Association completed.");
405 return 0;
406}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300407static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
408 void *arg)
409{
410 struct net_device *dev = arg;
411 struct wireless_dev *wdev;
412 struct wiphy *wiphy;
413 struct ieee80211_hw *hw;
414 struct wl1271 *wl;
415 struct wl1271 *wl_temp;
416 int ret = 0;
417
418 /* Check that this notification is for us. */
419 if (what != NETDEV_CHANGE)
420 return NOTIFY_DONE;
421
422 wdev = dev->ieee80211_ptr;
423 if (wdev == NULL)
424 return NOTIFY_DONE;
425
426 wiphy = wdev->wiphy;
427 if (wiphy == NULL)
428 return NOTIFY_DONE;
429
430 hw = wiphy_priv(wiphy);
431 if (hw == NULL)
432 return NOTIFY_DONE;
433
434 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200435 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300436 list_for_each_entry(wl, &wl_list, list) {
437 if (wl == wl_temp)
438 break;
439 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200440 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300441 if (wl != wl_temp)
442 return NOTIFY_DONE;
443
444 mutex_lock(&wl->mutex);
445
446 if (wl->state == WL1271_STATE_OFF)
447 goto out;
448
449 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
450 goto out;
451
Ido Yariva6208652011-03-01 15:14:41 +0200452 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 if (ret < 0)
454 goto out;
455
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300456 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300457
458 wl1271_ps_elp_sleep(wl);
459
460out:
461 mutex_unlock(&wl->mutex);
462
463 return NOTIFY_OK;
464}
465
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100466static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200467 struct regulatory_request *request)
468{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100469 struct ieee80211_supported_band *band;
470 struct ieee80211_channel *ch;
471 int i;
472
473 band = wiphy->bands[IEEE80211_BAND_5GHZ];
474 for (i = 0; i < band->n_channels; i++) {
475 ch = &band->channels[i];
476 if (ch->flags & IEEE80211_CHAN_DISABLED)
477 continue;
478
479 if (ch->flags & IEEE80211_CHAN_RADAR)
480 ch->flags |= IEEE80211_CHAN_NO_IBSS |
481 IEEE80211_CHAN_PASSIVE_SCAN;
482
483 }
484
485 return 0;
486}
487
Eliad Peller77ddaa12011-05-15 11:10:29 +0300488static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
489{
490 int ret = 0;
491
492 /* we should hold wl->mutex */
493 ret = wl1271_acx_ps_rx_streaming(wl, enable);
494 if (ret < 0)
495 goto out;
496
497 if (enable)
498 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
499 else
500 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
501out:
502 return ret;
503}
504
505/*
506 * this function is being called when the rx_streaming interval
507 * has beed changed or rx_streaming should be disabled
508 */
509int wl1271_recalc_rx_streaming(struct wl1271 *wl)
510{
511 int ret = 0;
512 int period = wl->conf.rx_streaming.interval;
513
514 /* don't reconfigure if rx_streaming is disabled */
515 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
516 goto out;
517
518 /* reconfigure/disable according to new streaming_period */
519 if (period &&
520 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
521 (wl->conf.rx_streaming.always ||
522 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
523 ret = wl1271_set_rx_streaming(wl, true);
524 else {
525 ret = wl1271_set_rx_streaming(wl, false);
526 /* don't cancel_work_sync since we might deadlock */
527 del_timer_sync(&wl->rx_streaming_timer);
528 }
529out:
530 return ret;
531}
532
533static void wl1271_rx_streaming_enable_work(struct work_struct *work)
534{
535 int ret;
536 struct wl1271 *wl =
537 container_of(work, struct wl1271, rx_streaming_enable_work);
538
539 mutex_lock(&wl->mutex);
540
541 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
542 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
543 (!wl->conf.rx_streaming.always &&
544 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
545 goto out;
546
547 if (!wl->conf.rx_streaming.interval)
548 goto out;
549
550 ret = wl1271_ps_elp_wakeup(wl);
551 if (ret < 0)
552 goto out;
553
554 ret = wl1271_set_rx_streaming(wl, true);
555 if (ret < 0)
556 goto out_sleep;
557
558 /* stop it after some time of inactivity */
559 mod_timer(&wl->rx_streaming_timer,
560 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
561
562out_sleep:
563 wl1271_ps_elp_sleep(wl);
564out:
565 mutex_unlock(&wl->mutex);
566}
567
568static void wl1271_rx_streaming_disable_work(struct work_struct *work)
569{
570 int ret;
571 struct wl1271 *wl =
572 container_of(work, struct wl1271, rx_streaming_disable_work);
573
574 mutex_lock(&wl->mutex);
575
576 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
577 goto out;
578
579 ret = wl1271_ps_elp_wakeup(wl);
580 if (ret < 0)
581 goto out;
582
583 ret = wl1271_set_rx_streaming(wl, false);
584 if (ret)
585 goto out_sleep;
586
587out_sleep:
588 wl1271_ps_elp_sleep(wl);
589out:
590 mutex_unlock(&wl->mutex);
591}
592
593static void wl1271_rx_streaming_timer(unsigned long data)
594{
595 struct wl1271 *wl = (struct wl1271 *)data;
596 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
597}
598
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300599static void wl1271_conf_init(struct wl1271 *wl)
600{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300601
602 /*
603 * This function applies the default configuration to the driver. This
604 * function is invoked upon driver load (spi probe.)
605 *
606 * The configuration is stored in a run-time structure in order to
607 * facilitate for run-time adjustment of any of the parameters. Making
608 * changes to the configuration structure will apply the new values on
609 * the next interface up (wl1271_op_start.)
610 */
611
612 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300613 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
Ido Yariv95dac04f2011-06-06 14:57:06 +0300615 /* Adjust settings according to optional module parameters */
616 if (fwlog_param) {
617 if (!strcmp(fwlog_param, "continuous")) {
618 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
619 } else if (!strcmp(fwlog_param, "ondemand")) {
620 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
621 } else if (!strcmp(fwlog_param, "dbgpins")) {
622 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
623 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
624 } else if (!strcmp(fwlog_param, "disable")) {
625 wl->conf.fwlog.mem_blocks = 0;
626 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
627 } else {
628 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
629 }
630 }
631}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300632
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633static int wl1271_plt_init(struct wl1271 *wl)
634{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200635 struct conf_tx_ac_category *conf_ac;
636 struct conf_tx_tid *conf_tid;
637 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638
Shahar Levi49d750ca2011-03-06 16:32:09 +0200639 if (wl->chip.id == CHIP_ID_1283_PG20)
640 ret = wl128x_cmd_general_parms(wl);
641 else
642 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200643 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200644 return ret;
645
Shahar Levi49d750ca2011-03-06 16:32:09 +0200646 if (wl->chip.id == CHIP_ID_1283_PG20)
647 ret = wl128x_cmd_radio_parms(wl);
648 else
649 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200650 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200651 return ret;
652
Shahar Levi49d750ca2011-03-06 16:32:09 +0200653 if (wl->chip.id != CHIP_ID_1283_PG20) {
654 ret = wl1271_cmd_ext_radio_parms(wl);
655 if (ret < 0)
656 return ret;
657 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200658 if (ret < 0)
659 return ret;
660
Shahar Levi48a61472011-03-06 16:32:08 +0200661 /* Chip-specific initializations */
662 ret = wl1271_chip_specific_init(wl);
663 if (ret < 0)
664 return ret;
665
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200666 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200667 if (ret < 0)
668 return ret;
669
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 ret = wl1271_acx_init_mem_config(wl);
671 if (ret < 0)
672 return ret;
673
Luciano Coelho12419cc2010-02-18 13:25:44 +0200674 /* PHY layer config */
675 ret = wl1271_init_phy_config(wl);
676 if (ret < 0)
677 goto out_free_memmap;
678
679 ret = wl1271_acx_dco_itrim_params(wl);
680 if (ret < 0)
681 goto out_free_memmap;
682
683 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200684 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200685 if (ret < 0)
686 goto out_free_memmap;
687
688 /* Bluetooth WLAN coexistence */
689 ret = wl1271_init_pta(wl);
690 if (ret < 0)
691 goto out_free_memmap;
692
Shahar Leviff868432011-04-11 15:41:46 +0300693 /* FM WLAN coexistence */
694 ret = wl1271_acx_fm_coex(wl);
695 if (ret < 0)
696 goto out_free_memmap;
697
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 /* Energy detection */
699 ret = wl1271_init_energy_detection(wl);
700 if (ret < 0)
701 goto out_free_memmap;
702
Eliad Peller7f0979882011-08-14 13:17:06 +0300703 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600704 if (ret < 0)
705 goto out_free_memmap;
706
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100708 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200709 if (ret < 0)
710 goto out_free_memmap;
711
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200712 /* Default TID/AC configuration */
713 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200714 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200715 conf_ac = &wl->conf.tx.ac_conf[i];
716 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
717 conf_ac->cw_max, conf_ac->aifsn,
718 conf_ac->tx_op_limit);
719 if (ret < 0)
720 goto out_free_memmap;
721
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 conf_tid = &wl->conf.tx.tid_conf[i];
723 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
724 conf_tid->channel_type,
725 conf_tid->tsid,
726 conf_tid->ps_scheme,
727 conf_tid->ack_policy,
728 conf_tid->apsd_conf[0],
729 conf_tid->apsd_conf[1]);
730 if (ret < 0)
731 goto out_free_memmap;
732 }
733
Luciano Coelho12419cc2010-02-18 13:25:44 +0200734 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200735 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200737 goto out_free_memmap;
738
739 /* Configure for CAM power saving (ie. always active) */
740 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
741 if (ret < 0)
742 goto out_free_memmap;
743
744 /* configure PM */
745 ret = wl1271_acx_pm_config(wl);
746 if (ret < 0)
747 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750
751 out_free_memmap:
752 kfree(wl->target_mem_map);
753 wl->target_mem_map = NULL;
754
755 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300756}
757
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300758static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200759{
760 bool fw_ps;
761
762 /* only regulate station links */
763 if (hlid < WL1271_AP_STA_HLID_START)
764 return;
765
766 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
767
768 /*
769 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300770 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200771 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300772 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200773 wl1271_ps_link_end(wl, hlid);
774
775 /* Start high-level PS if the STA is asleep with enough blocks in FW */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300776 else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777 wl1271_ps_link_start(wl, hlid, true);
778}
779
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300780bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
781{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300782 int id;
783
784 /* global/broadcast "stations" are always active */
785 if (hlid < WL1271_AP_STA_HLID_START)
786 return true;
787
788 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300789 return test_bit(id, wl->ap_hlid_map);
790}
791
792static void wl12xx_irq_update_links_status(struct wl1271 *wl,
793 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200794{
795 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300796 u8 hlid, cnt;
797
798 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200799
800 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
801 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
802 wl1271_debug(DEBUG_PSM,
803 "link ps prev 0x%x cur 0x%x changed 0x%x",
804 wl->ap_fw_ps_map, cur_fw_ps_map,
805 wl->ap_fw_ps_map ^ cur_fw_ps_map);
806
807 wl->ap_fw_ps_map = cur_fw_ps_map;
808 }
809
810 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300811 if (!wl1271_is_active_sta(wl, hlid))
812 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200813
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300814 cnt = status->tx_lnk_free_pkts[hlid] -
815 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200816
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300817 wl->links[hlid].prev_freed_pkts =
818 status->tx_lnk_free_pkts[hlid];
819 wl->links[hlid].allocated_pkts -= cnt;
820
821 wl12xx_irq_ps_regulate_link(wl, hlid,
822 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823 }
824}
825
Eliad Peller4d56ad92011-08-14 13:17:05 +0300826static void wl12xx_fw_status(struct wl1271 *wl,
827 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200829 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200830 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300831 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300832 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833
Eliad Peller4d56ad92011-08-14 13:17:05 +0300834 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200835
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
837 "drv_rx_counter = %d, tx_results_counter = %d)",
838 status->intr,
839 status->fw_rx_counter,
840 status->drv_rx_counter,
841 status->tx_results_counter);
842
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300843 for (i = 0; i < NUM_TX_QUEUES; i++) {
844 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300845 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300846 (status->tx_released_pkts[i] -
847 wl->tx_pkts_freed[i]) & 0xff;
848
849 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
850 }
851
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300852 /* prevent wrap-around in total blocks counter */
853 if (likely(wl->tx_blocks_freed <=
854 le32_to_cpu(status->total_released_blks)))
855 freed_blocks = le32_to_cpu(status->total_released_blks) -
856 wl->tx_blocks_freed;
857 else
858 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
859 le32_to_cpu(status->total_released_blks);
860
Eliad Peller4d56ad92011-08-14 13:17:05 +0300861 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200862
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300863 wl->tx_allocated_blocks -= freed_blocks;
864
Eliad Peller4d56ad92011-08-14 13:17:05 +0300865 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200866
Eliad Peller4d56ad92011-08-14 13:17:05 +0300867 /*
868 * The FW might change the total number of TX memblocks before
869 * we get a notification about blocks being released. Thus, the
870 * available blocks calculation might yield a temporary result
871 * which is lower than the actual available blocks. Keeping in
872 * mind that only blocks that were allocated can be moved from
873 * TX to RX, tx_blocks_available should never decrease here.
874 */
875 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
876 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877
Ido Yariva5225502010-10-12 14:49:10 +0200878 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200879 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200880 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
Eliad Peller4d56ad92011-08-14 13:17:05 +0300882 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300883 if (wl->bss_type == BSS_TYPE_AP_BSS)
884 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200887 getnstimeofday(&ts);
888 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
889 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890}
891
Ido Yariva6208652011-03-01 15:14:41 +0200892static void wl1271_flush_deferred_work(struct wl1271 *wl)
893{
894 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200895
Ido Yariva6208652011-03-01 15:14:41 +0200896 /* Pass all received frames to the network stack */
897 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
898 ieee80211_rx_ni(wl->hw, skb);
899
900 /* Return sent skbs to the network stack */
901 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300902 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200903}
904
905static void wl1271_netstack_work(struct work_struct *work)
906{
907 struct wl1271 *wl =
908 container_of(work, struct wl1271, netstack_work);
909
910 do {
911 wl1271_flush_deferred_work(wl);
912 } while (skb_queue_len(&wl->deferred_rx_queue));
913}
914
915#define WL1271_IRQ_MAX_LOOPS 256
916
917irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300920 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200921 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200922 struct wl1271 *wl = (struct wl1271 *)cookie;
923 bool done = false;
924 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200925 unsigned long flags;
926
927 /* TX might be handled here, avoid redundant work */
928 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
929 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930
Ido Yariv341b7cd2011-03-31 10:07:01 +0200931 /*
932 * In case edge triggered interrupt must be used, we cannot iterate
933 * more than once without introducing race conditions with the hardirq.
934 */
935 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
936 loopcount = 1;
937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938 mutex_lock(&wl->mutex);
939
940 wl1271_debug(DEBUG_IRQ, "IRQ work");
941
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200942 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943 goto out;
944
Ido Yariva6208652011-03-01 15:14:41 +0200945 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 if (ret < 0)
947 goto out;
948
Ido Yariva6208652011-03-01 15:14:41 +0200949 while (!done && loopcount--) {
950 /*
951 * In order to avoid a race with the hardirq, clear the flag
952 * before acknowledging the chip. Since the mutex is held,
953 * wl1271_ps_elp_wakeup cannot be called concurrently.
954 */
955 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
956 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200957
Eliad Peller4d56ad92011-08-14 13:17:05 +0300958 wl12xx_fw_status(wl, wl->fw_status);
959 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200960 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200961 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200962 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 continue;
964 }
965
Eliad Pellerccc83b02010-10-27 14:09:57 +0200966 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
967 wl1271_error("watchdog interrupt received! "
968 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300969 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200970
971 /* restarting the chip. ignore any other interrupt. */
972 goto out;
973 }
974
Ido Yariva6208652011-03-01 15:14:41 +0200975 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200976 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
977
Eliad Peller4d56ad92011-08-14 13:17:05 +0300978 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200979
Ido Yariva5225502010-10-12 14:49:10 +0200980 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200981 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200982 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300983 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200984 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200985 /*
986 * In order to avoid starvation of the TX path,
987 * call the work function directly.
988 */
989 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200990 } else {
991 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200992 }
993
Ido Yariv8aad2462011-03-01 15:14:38 +0200994 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300995 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200996 (wl->tx_results_count & 0xff))
997 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200998
999 /* Make sure the deferred queues don't get too long */
1000 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1001 skb_queue_len(&wl->deferred_rx_queue);
1002 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1003 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001004 }
1005
1006 if (intr & WL1271_ACX_INTR_EVENT_A) {
1007 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1008 wl1271_event_handle(wl, 0);
1009 }
1010
1011 if (intr & WL1271_ACX_INTR_EVENT_B) {
1012 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1013 wl1271_event_handle(wl, 1);
1014 }
1015
1016 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1017 wl1271_debug(DEBUG_IRQ,
1018 "WL1271_ACX_INTR_INIT_COMPLETE");
1019
1020 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1021 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 }
1023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 wl1271_ps_elp_sleep(wl);
1025
1026out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001027 spin_lock_irqsave(&wl->wl_lock, flags);
1028 /* In case TX was not handled here, queue TX work */
1029 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1030 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001031 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001032 ieee80211_queue_work(wl->hw, &wl->tx_work);
1033 spin_unlock_irqrestore(&wl->wl_lock, flags);
1034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001036
1037 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038}
Ido Yariva6208652011-03-01 15:14:41 +02001039EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041static int wl1271_fetch_firmware(struct wl1271 *wl)
1042{
1043 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001044 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 int ret;
1046
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001047 if (wl->chip.id == CHIP_ID_1283_PG20)
1048 fw_name = WL128X_FW_NAME;
1049 else
1050 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001051
1052 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1053
1054 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 if (ret < 0) {
1057 wl1271_error("could not get firmware: %d", ret);
1058 return ret;
1059 }
1060
1061 if (fw->size % 4) {
1062 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1063 fw->size);
1064 ret = -EILSEQ;
1065 goto out;
1066 }
1067
Arik Nemtsov166d5042010-10-16 21:44:57 +02001068 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001070 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071
1072 if (!wl->fw) {
1073 wl1271_error("could not allocate memory for the firmware");
1074 ret = -ENOMEM;
1075 goto out;
1076 }
1077
1078 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 ret = 0;
1080
1081out:
1082 release_firmware(fw);
1083
1084 return ret;
1085}
1086
1087static int wl1271_fetch_nvs(struct wl1271 *wl)
1088{
1089 const struct firmware *fw;
1090 int ret;
1091
Shahar Levi5aa42342011-03-06 16:32:07 +02001092 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093
1094 if (ret < 0) {
1095 wl1271_error("could not get nvs file: %d", ret);
1096 return ret;
1097 }
1098
Shahar Levibc765bf2011-03-06 16:32:10 +02001099 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100
1101 if (!wl->nvs) {
1102 wl1271_error("could not allocate memory for the nvs file");
1103 ret = -ENOMEM;
1104 goto out;
1105 }
1106
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001107 wl->nvs_len = fw->size;
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109out:
1110 release_firmware(fw);
1111
1112 return ret;
1113}
1114
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001115void wl12xx_queue_recovery_work(struct wl1271 *wl)
1116{
1117 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1118 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1119}
1120
Ido Yariv95dac04f2011-06-06 14:57:06 +03001121size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1122{
1123 size_t len = 0;
1124
1125 /* The FW log is a length-value list, find where the log end */
1126 while (len < maxlen) {
1127 if (memblock[len] == 0)
1128 break;
1129 if (len + memblock[len] + 1 > maxlen)
1130 break;
1131 len += memblock[len] + 1;
1132 }
1133
1134 /* Make sure we have enough room */
1135 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1136
1137 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1138 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1139 wl->fwlog_size += len;
1140
1141 return len;
1142}
1143
1144static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1145{
1146 u32 addr;
1147 u32 first_addr;
1148 u8 *block;
1149
1150 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1151 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1152 (wl->conf.fwlog.mem_blocks == 0))
1153 return;
1154
1155 wl1271_info("Reading FW panic log");
1156
1157 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1158 if (!block)
1159 return;
1160
1161 /*
1162 * Make sure the chip is awake and the logger isn't active.
1163 * This might fail if the firmware hanged.
1164 */
1165 if (!wl1271_ps_elp_wakeup(wl))
1166 wl12xx_cmd_stop_fwlog(wl);
1167
1168 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001169 wl12xx_fw_status(wl, wl->fw_status);
1170 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001171 if (!first_addr)
1172 goto out;
1173
1174 /* Traverse the memory blocks linked list */
1175 addr = first_addr;
1176 do {
1177 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1178 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1179 false);
1180
1181 /*
1182 * Memory blocks are linked to one another. The first 4 bytes
1183 * of each memory block hold the hardware address of the next
1184 * one. The last memory block points to the first one.
1185 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001186 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001187 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1188 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1189 break;
1190 } while (addr && (addr != first_addr));
1191
1192 wake_up_interruptible(&wl->fwlog_waitq);
1193
1194out:
1195 kfree(block);
1196}
1197
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001198static void wl1271_recovery_work(struct work_struct *work)
1199{
1200 struct wl1271 *wl =
1201 container_of(work, struct wl1271, recovery_work);
1202
1203 mutex_lock(&wl->mutex);
1204
1205 if (wl->state != WL1271_STATE_ON)
1206 goto out;
1207
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001208 /* Avoid a recursive recovery */
1209 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1210
Ido Yariv95dac04f2011-06-06 14:57:06 +03001211 wl12xx_read_fwlog_panic(wl);
1212
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001213 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1214 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001215
Oz Krakowskib992c682011-06-26 10:36:02 +03001216 /*
1217 * Advance security sequence number to overcome potential progress
1218 * in the firmware during recovery. This doens't hurt if the network is
1219 * not encrypted.
1220 */
1221 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1222 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1223 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1224
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001225 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1226 ieee80211_connection_loss(wl->vif);
1227
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001228 /* Prevent spurious TX during FW restart */
1229 ieee80211_stop_queues(wl->hw);
1230
Luciano Coelho33c2c062011-05-10 14:46:02 +03001231 if (wl->sched_scanning) {
1232 ieee80211_sched_scan_stopped(wl->hw);
1233 wl->sched_scanning = false;
1234 }
1235
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001236 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001237 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001238
1239 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1240
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241 ieee80211_restart_hw(wl->hw);
1242
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001243 /*
1244 * Its safe to enable TX now - the queues are stopped after a request
1245 * to restart the HW.
1246 */
1247 ieee80211_wake_queues(wl->hw);
1248
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001249out:
1250 mutex_unlock(&wl->mutex);
1251}
1252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253static void wl1271_fw_wakeup(struct wl1271 *wl)
1254{
1255 u32 elp_reg;
1256
1257 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001258 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259}
1260
1261static int wl1271_setup(struct wl1271 *wl)
1262{
1263 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1264 if (!wl->fw_status)
1265 return -ENOMEM;
1266
1267 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1268 if (!wl->tx_res_if) {
1269 kfree(wl->fw_status);
1270 return -ENOMEM;
1271 }
1272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 return 0;
1274}
1275
1276static int wl1271_chip_wakeup(struct wl1271 *wl)
1277{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001278 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 int ret = 0;
1280
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001281 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001282 ret = wl1271_power_on(wl);
1283 if (ret < 0)
1284 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001286 wl1271_io_reset(wl);
1287 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288
1289 /* We don't need a real memory partition here, because we only want
1290 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001291 memset(&partition, 0, sizeof(partition));
1292 partition.reg.start = REGISTERS_BASE;
1293 partition.reg.size = REGISTERS_DOWN_SIZE;
1294 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295
1296 /* ELP module wake up */
1297 wl1271_fw_wakeup(wl);
1298
1299 /* whal_FwCtrl_BootSm() */
1300
1301 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001302 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303
1304 /* 1. check if chip id is valid */
1305
1306 switch (wl->chip.id) {
1307 case CHIP_ID_1271_PG10:
1308 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1309 wl->chip.id);
1310
1311 ret = wl1271_setup(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 break;
1315 case CHIP_ID_1271_PG20:
1316 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1317 wl->chip.id);
1318
Shahar Levi0c005042011-06-12 10:34:43 +03001319 /*
1320 * 'end-of-transaction flag' and 'LPD mode flag'
1321 * should be set in wl127x AP mode only
1322 */
Shahar Levi564f5952011-04-04 10:20:39 +03001323 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001324 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1325 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 ret = wl1271_setup(wl);
1328 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001331 case CHIP_ID_1283_PG20:
1332 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1333 wl->chip.id);
1334
1335 ret = wl1271_setup(wl);
1336 if (ret < 0)
1337 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001338
Ido Yariv0da13da2011-03-31 10:06:58 +02001339 if (wl1271_set_block_size(wl))
1340 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001341 break;
1342 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001346 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 }
1348
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001349 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 ret = wl1271_fetch_firmware(wl);
1351 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 }
1354
1355 /* No NVS from netlink, try to get it from the filesystem */
1356 if (wl->nvs == NULL) {
1357 ret = wl1271_fetch_nvs(wl);
1358 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 }
1361
1362out:
1363 return ret;
1364}
1365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366int wl1271_plt_start(struct wl1271 *wl)
1367{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001369 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 int ret;
1371
1372 mutex_lock(&wl->mutex);
1373
1374 wl1271_notice("power up");
1375
1376 if (wl->state != WL1271_STATE_OFF) {
1377 wl1271_error("cannot go into PLT state because not "
1378 "in off state: %d", wl->state);
1379 ret = -EBUSY;
1380 goto out;
1381 }
1382
Arik Nemtsov166d5042010-10-16 21:44:57 +02001383 wl->bss_type = BSS_TYPE_STA_BSS;
1384
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 while (retries) {
1386 retries--;
1387 ret = wl1271_chip_wakeup(wl);
1388 if (ret < 0)
1389 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391 ret = wl1271_boot(wl);
1392 if (ret < 0)
1393 goto power_off;
1394
1395 ret = wl1271_plt_init(wl);
1396 if (ret < 0)
1397 goto irq_disable;
1398
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001399 wl->state = WL1271_STATE_PLT;
1400 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001401 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001402
Gery Kahn6f07b722011-07-18 14:21:49 +03001403 /* update hw/fw version info in wiphy struct */
1404 wiphy->hw_version = wl->chip.id;
1405 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1406 sizeof(wiphy->fw_version));
1407
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408 goto out;
1409
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001410irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 mutex_unlock(&wl->mutex);
1412 /* Unlocking the mutex in the middle of handling is
1413 inherently unsafe. In this case we deem it safe to do,
1414 because we need to let any possibly pending IRQ out of
1415 the system (and while we are WL1271_STATE_OFF the IRQ
1416 work function will not do anything.) Also, any other
1417 possible concurrent operations will fail due to the
1418 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001419 wl1271_disable_interrupts(wl);
1420 wl1271_flush_deferred_work(wl);
1421 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422 mutex_lock(&wl->mutex);
1423power_off:
1424 wl1271_power_off(wl);
1425 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001427 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1428 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429out:
1430 mutex_unlock(&wl->mutex);
1431
1432 return ret;
1433}
1434
Luciano Coelho4623ec72011-03-21 19:26:41 +02001435static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436{
1437 int ret = 0;
1438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 wl1271_notice("power down");
1440
1441 if (wl->state != WL1271_STATE_PLT) {
1442 wl1271_error("cannot power down because not in PLT "
1443 "state: %d", wl->state);
1444 ret = -EBUSY;
1445 goto out;
1446 }
1447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448 wl1271_power_off(wl);
1449
1450 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001451 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001454 wl1271_disable_interrupts(wl);
1455 wl1271_flush_deferred_work(wl);
1456 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001457 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001458 mutex_lock(&wl->mutex);
1459out:
1460 return ret;
1461}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001462
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001463int wl1271_plt_stop(struct wl1271 *wl)
1464{
1465 int ret;
1466
1467 mutex_lock(&wl->mutex);
1468 ret = __wl1271_plt_stop(wl);
1469 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 return ret;
1471}
1472
Johannes Berg7bb45682011-02-24 14:42:06 +01001473static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474{
1475 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001476 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001477 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001478 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001480 mapping = skb_get_queue_mapping(skb);
1481 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001482
1483 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001484 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001485
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001486 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001487
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001488 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001489
1490 /*
1491 * The workqueue is slow to process the tx_queue and we need stop
1492 * the queue here, otherwise the queue will get too long.
1493 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001494 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001495 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1496 ieee80211_stop_queue(wl->hw, mapping);
1497 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001498 }
1499
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
1515 /*
1516 * The chip specific setup must run before the first TX packet -
1517 * before that, the tx_work will not be initialized!
1518 */
1519
Ido Yarivb07d4032011-03-01 15:14:43 +02001520 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1521 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001522 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001523
Arik Nemtsov04216da2011-08-14 13:17:38 +03001524out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001525 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526}
1527
Shahar Leviae47c452011-03-06 16:32:14 +02001528int wl1271_tx_dummy_packet(struct wl1271 *wl)
1529{
Ido Yariv990f5de2011-03-31 10:06:59 +02001530 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001531 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001532
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 spin_lock_irqsave(&wl->wl_lock, flags);
1534 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001535 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001536 spin_unlock_irqrestore(&wl->wl_lock, flags);
1537
1538 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1539 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1540 wl1271_tx_work_locked(wl);
1541
1542 /*
1543 * If the FW TX is busy, TX work will be scheduled by the threaded
1544 * interrupt handler function
1545 */
1546 return 0;
1547}
1548
1549/*
1550 * The size of the dummy packet should be at least 1400 bytes. However, in
1551 * order to minimize the number of bus transactions, aligning it to 512 bytes
1552 * boundaries could be beneficial, performance wise
1553 */
1554#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1555
Luciano Coelhocf27d862011-04-01 21:08:23 +03001556static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001557{
1558 struct sk_buff *skb;
1559 struct ieee80211_hdr_3addr *hdr;
1560 unsigned int dummy_packet_size;
1561
1562 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1563 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1564
1565 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001566 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001567 wl1271_warning("Failed to allocate a dummy packet skb");
1568 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001569 }
1570
1571 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1572
1573 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1574 memset(hdr, 0, sizeof(*hdr));
1575 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 IEEE80211_STYPE_NULLFUNC |
1577 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001578
Ido Yariv990f5de2011-03-31 10:06:59 +02001579 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001580
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001581 /* Dummy packets require the TID to be management */
1582 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001583
1584 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001585 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001586 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001589}
1590
Ido Yariv990f5de2011-03-31 10:06:59 +02001591
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001592static struct notifier_block wl1271_dev_notifier = {
1593 .notifier_call = wl1271_dev_notify,
1594};
1595
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001596#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001597static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001598{
Eliad Pellere85d1622011-06-27 13:06:43 +03001599 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001600
Eliad Peller94390642011-05-13 11:57:13 +03001601 mutex_lock(&wl->mutex);
1602
Eliad Pellere85d1622011-06-27 13:06:43 +03001603 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1604 goto out_unlock;
1605
Eliad Peller94390642011-05-13 11:57:13 +03001606 ret = wl1271_ps_elp_wakeup(wl);
1607 if (ret < 0)
1608 goto out_unlock;
1609
1610 /* enter psm if needed*/
1611 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1612 DECLARE_COMPLETION_ONSTACK(compl);
1613
1614 wl->ps_compl = &compl;
1615 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1616 wl->basic_rate, true);
1617 if (ret < 0)
1618 goto out_sleep;
1619
1620 /* we must unlock here so we will be able to get events */
1621 wl1271_ps_elp_sleep(wl);
1622 mutex_unlock(&wl->mutex);
1623
1624 ret = wait_for_completion_timeout(
1625 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1626 if (ret <= 0) {
1627 wl1271_warning("couldn't enter ps mode!");
1628 ret = -EBUSY;
1629 goto out;
1630 }
1631
1632 /* take mutex again, and wakeup */
1633 mutex_lock(&wl->mutex);
1634
1635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
1637 goto out_unlock;
1638 }
1639out_sleep:
1640 wl1271_ps_elp_sleep(wl);
1641out_unlock:
1642 mutex_unlock(&wl->mutex);
1643out:
1644 return ret;
1645
1646}
1647
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001648static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001649{
Eliad Pellere85d1622011-06-27 13:06:43 +03001650 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001651
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001652 mutex_lock(&wl->mutex);
1653
Eliad Pellere85d1622011-06-27 13:06:43 +03001654 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1655 goto out_unlock;
1656
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001657 ret = wl1271_ps_elp_wakeup(wl);
1658 if (ret < 0)
1659 goto out_unlock;
1660
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001661 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001662
1663 wl1271_ps_elp_sleep(wl);
1664out_unlock:
1665 mutex_unlock(&wl->mutex);
1666 return ret;
1667
1668}
1669
1670static int wl1271_configure_suspend(struct wl1271 *wl)
1671{
1672 if (wl->bss_type == BSS_TYPE_STA_BSS)
1673 return wl1271_configure_suspend_sta(wl);
1674 if (wl->bss_type == BSS_TYPE_AP_BSS)
1675 return wl1271_configure_suspend_ap(wl);
1676 return 0;
1677}
1678
1679static void wl1271_configure_resume(struct wl1271 *wl)
1680{
1681 int ret;
1682 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1683 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1684
1685 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001686 return;
1687
1688 mutex_lock(&wl->mutex);
1689 ret = wl1271_ps_elp_wakeup(wl);
1690 if (ret < 0)
1691 goto out;
1692
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693 if (is_sta) {
1694 /* exit psm if it wasn't configured */
1695 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1696 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1697 wl->basic_rate, true);
1698 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001699 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001700 }
Eliad Peller94390642011-05-13 11:57:13 +03001701
1702 wl1271_ps_elp_sleep(wl);
1703out:
1704 mutex_unlock(&wl->mutex);
1705}
1706
Eliad Peller402e48612011-05-13 11:57:09 +03001707static int wl1271_op_suspend(struct ieee80211_hw *hw,
1708 struct cfg80211_wowlan *wow)
1709{
1710 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001711 int ret;
1712
Eliad Peller402e48612011-05-13 11:57:09 +03001713 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001714 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001715
Eliad Peller4a859df2011-06-06 12:21:52 +03001716 wl->wow_enabled = true;
1717 ret = wl1271_configure_suspend(wl);
1718 if (ret < 0) {
1719 wl1271_warning("couldn't prepare device to suspend");
1720 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001721 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001722 /* flush any remaining work */
1723 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001724
1725 /*
1726 * disable and re-enable interrupts in order to flush
1727 * the threaded_irq
1728 */
1729 wl1271_disable_interrupts(wl);
1730
1731 /*
1732 * set suspended flag to avoid triggering a new threaded_irq
1733 * work. no need for spinlock as interrupts are disabled.
1734 */
1735 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1736
1737 wl1271_enable_interrupts(wl);
1738 flush_work(&wl->tx_work);
1739 flush_delayed_work(&wl->pspoll_work);
1740 flush_delayed_work(&wl->elp_work);
1741
Eliad Peller402e48612011-05-13 11:57:09 +03001742 return 0;
1743}
1744
1745static int wl1271_op_resume(struct ieee80211_hw *hw)
1746{
1747 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001748 unsigned long flags;
1749 bool run_irq_work = false;
1750
Eliad Peller402e48612011-05-13 11:57:09 +03001751 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1752 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001753 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001754
1755 /*
1756 * re-enable irq_work enqueuing, and call irq_work directly if
1757 * there is a pending work.
1758 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001759 spin_lock_irqsave(&wl->wl_lock, flags);
1760 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1761 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1762 run_irq_work = true;
1763 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001764
Eliad Peller4a859df2011-06-06 12:21:52 +03001765 if (run_irq_work) {
1766 wl1271_debug(DEBUG_MAC80211,
1767 "run postponed irq_work directly");
1768 wl1271_irq(0, wl);
1769 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001770 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001772 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001773
Eliad Peller402e48612011-05-13 11:57:09 +03001774 return 0;
1775}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001776#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001778static int wl1271_op_start(struct ieee80211_hw *hw)
1779{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001780 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1781
1782 /*
1783 * We have to delay the booting of the hardware because
1784 * we need to know the local MAC address before downloading and
1785 * initializing the firmware. The MAC address cannot be changed
1786 * after boot, and without the proper MAC address, the firmware
1787 * will not function properly.
1788 *
1789 * The MAC address is first known when the corresponding interface
1790 * is added. That is where we will initialize the hardware.
1791 */
1792
1793 return 0;
1794}
1795
1796static void wl1271_op_stop(struct ieee80211_hw *hw)
1797{
1798 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1799}
1800
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001801static u8 wl12xx_get_role_type(struct wl1271 *wl)
1802{
1803 switch (wl->bss_type) {
1804 case BSS_TYPE_AP_BSS:
1805 return WL1271_ROLE_AP;
1806
1807 case BSS_TYPE_STA_BSS:
1808 return WL1271_ROLE_STA;
1809
Eliad Peller227e81e2011-08-14 13:17:26 +03001810 case BSS_TYPE_IBSS:
1811 return WL1271_ROLE_IBSS;
1812
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001813 default:
1814 wl1271_error("invalid bss_type: %d", wl->bss_type);
1815 }
1816 return WL12XX_INVALID_ROLE_TYPE;
1817}
1818
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001819static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1820 struct ieee80211_vif *vif)
1821{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001823 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001824 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001826 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001827 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001829 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1830 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831
1832 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001833 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001834 wl1271_debug(DEBUG_MAC80211,
1835 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001836 ret = -EBUSY;
1837 goto out;
1838 }
1839
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001840 /*
1841 * in some very corner case HW recovery scenarios its possible to
1842 * get here before __wl1271_op_remove_interface is complete, so
1843 * opt out if that is the case.
1844 */
1845 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1846 ret = -EBUSY;
1847 goto out;
1848 }
1849
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001850 switch (vif->type) {
1851 case NL80211_IFTYPE_STATION:
1852 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001853 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001854 break;
1855 case NL80211_IFTYPE_ADHOC:
1856 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001857 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001858 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001859 case NL80211_IFTYPE_AP:
1860 wl->bss_type = BSS_TYPE_AP_BSS;
1861 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001862 default:
1863 ret = -EOPNOTSUPP;
1864 goto out;
1865 }
1866
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001867 role_type = wl12xx_get_role_type(wl);
1868 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1869 ret = -EINVAL;
1870 goto out;
1871 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001872 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873
1874 if (wl->state != WL1271_STATE_OFF) {
1875 wl1271_error("cannot start because not in off state: %d",
1876 wl->state);
1877 ret = -EBUSY;
1878 goto out;
1879 }
1880
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001881 while (retries) {
1882 retries--;
1883 ret = wl1271_chip_wakeup(wl);
1884 if (ret < 0)
1885 goto power_off;
1886
1887 ret = wl1271_boot(wl);
1888 if (ret < 0)
1889 goto power_off;
1890
Eliad Peller227e81e2011-08-14 13:17:26 +03001891 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1892 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001893 /*
1894 * The device role is a special role used for
1895 * rx and tx frames prior to association (as
1896 * the STA role can get packets only from
1897 * its associated bssid)
1898 */
1899 ret = wl12xx_cmd_role_enable(wl,
1900 WL1271_ROLE_DEVICE,
1901 &wl->dev_role_id);
1902 if (ret < 0)
1903 goto irq_disable;
1904 }
1905
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1907 if (ret < 0)
1908 goto irq_disable;
1909
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001910 ret = wl1271_hw_init(wl);
1911 if (ret < 0)
1912 goto irq_disable;
1913
Eliad Peller71125ab2010-10-28 21:46:43 +02001914 booted = true;
1915 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001917irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001918 mutex_unlock(&wl->mutex);
1919 /* Unlocking the mutex in the middle of handling is
1920 inherently unsafe. In this case we deem it safe to do,
1921 because we need to let any possibly pending IRQ out of
1922 the system (and while we are WL1271_STATE_OFF the IRQ
1923 work function will not do anything.) Also, any other
1924 possible concurrent operations will fail due to the
1925 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001926 wl1271_disable_interrupts(wl);
1927 wl1271_flush_deferred_work(wl);
1928 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001929 mutex_lock(&wl->mutex);
1930power_off:
1931 wl1271_power_off(wl);
1932 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001933
Eliad Peller71125ab2010-10-28 21:46:43 +02001934 if (!booted) {
1935 wl1271_error("firmware boot failed despite %d retries",
1936 WL1271_BOOT_RETRIES);
1937 goto out;
1938 }
1939
1940 wl->vif = vif;
1941 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001942 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001943 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001944
1945 /* update hw/fw version info in wiphy struct */
1946 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001947 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001948 sizeof(wiphy->fw_version));
1949
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001950 /*
1951 * Now we know if 11a is supported (info from the NVS), so disable
1952 * 11a channels if not supported
1953 */
1954 if (!wl->enable_11a)
1955 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1956
1957 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1958 wl->enable_11a ? "" : "not ");
1959
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001960out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 mutex_unlock(&wl->mutex);
1962
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001963 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001964 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001965 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001966 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 return ret;
1969}
1970
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001971static void __wl1271_op_remove_interface(struct wl1271 *wl,
1972 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001974 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001976 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001978 /* because of hardware recovery, we may get here twice */
1979 if (wl->state != WL1271_STATE_ON)
1980 return;
1981
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001982 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001984 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001985 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001986 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001987
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001988 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001989 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001990 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001991
Luciano Coelho08688d62010-07-08 17:50:07 +03001992 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001993 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001994 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001995 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001996 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 }
1998
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001999 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2000 /* disable active roles */
2001 ret = wl1271_ps_elp_wakeup(wl);
2002 if (ret < 0)
2003 goto deinit;
2004
Eliad Peller04e80792011-08-14 13:17:09 +03002005 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2006 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2007 if (ret < 0)
2008 goto deinit;
2009 }
2010
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002011 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2012 if (ret < 0)
2013 goto deinit;
2014
2015 wl1271_ps_elp_sleep(wl);
2016 }
2017deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002018 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002019 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002020 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002021 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2022 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002023
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002024 /*
2025 * this must be before the cancel_work calls below, so that the work
2026 * functions don't perform further work.
2027 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028 wl->state = WL1271_STATE_OFF;
2029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 mutex_unlock(&wl->mutex);
2031
Ido Yariva6208652011-03-01 15:14:41 +02002032 wl1271_disable_interrupts(wl);
2033 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002034 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002035 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002037 del_timer_sync(&wl->rx_streaming_timer);
2038 cancel_work_sync(&wl->rx_streaming_enable_work);
2039 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002040 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002041 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042
2043 mutex_lock(&wl->mutex);
2044
2045 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002046 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl1271_power_off(wl);
2048
2049 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002050 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002053 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002054 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055
2056 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002057 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2059 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002060 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 wl->tx_results_count = 0;
2062 wl->tx_packets_count = 0;
2063 wl->time_offset = 0;
2064 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002065 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002066 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002067 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002068 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002069 wl->ap_fw_ps_map = 0;
2070 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002071 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002072 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002073 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002074 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2075 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002076 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002077
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002078 /* The system link is always allocated */
2079 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2080
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002081 /*
2082 * this is performed after the cancel_work calls and the associated
2083 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2084 * get executed before all these vars have been reset.
2085 */
2086 wl->flags = 0;
2087
Eliad Peller4d56ad92011-08-14 13:17:05 +03002088 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002089
Arik Nemtsov742246f2011-08-14 13:17:33 +03002090 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002091 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002092 wl->tx_allocated_pkts[i] = 0;
2093 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002094
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002096
2097 kfree(wl->fw_status);
2098 wl->fw_status = NULL;
2099 kfree(wl->tx_res_if);
2100 wl->tx_res_if = NULL;
2101 kfree(wl->target_mem_map);
2102 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002103}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002104
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002105static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2106 struct ieee80211_vif *vif)
2107{
2108 struct wl1271 *wl = hw->priv;
2109
2110 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002111 /*
2112 * wl->vif can be null here if someone shuts down the interface
2113 * just when hardware recovery has been started.
2114 */
2115 if (wl->vif) {
2116 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002117 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002118 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002119
Juuso Oikarinen67353292010-11-18 15:19:02 +02002120 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002121 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122}
2123
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002124static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002125{
2126 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002127 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002128
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002129 /*
2130 * One of the side effects of the JOIN command is that is clears
2131 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2132 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002133 * Currently the only valid scenario for JOIN during association
2134 * is on roaming, in which case we will also be given new keys.
2135 * Keep the below message for now, unless it starts bothering
2136 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002137 */
2138 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2139 wl1271_info("JOIN while associated.");
2140
2141 if (set_assoc)
2142 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2143
Eliad Peller227e81e2011-08-14 13:17:26 +03002144 if (is_ibss)
2145 ret = wl12xx_cmd_role_start_ibss(wl);
2146 else
2147 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002148 if (ret < 0)
2149 goto out;
2150
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002151 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2152 goto out;
2153
2154 /*
2155 * The join command disable the keep-alive mode, shut down its process,
2156 * and also clear the template config, so we need to reset it all after
2157 * the join. The acx_aid starts the keep-alive process, and the order
2158 * of the commands below is relevant.
2159 */
2160 ret = wl1271_acx_keep_alive_mode(wl, true);
2161 if (ret < 0)
2162 goto out;
2163
2164 ret = wl1271_acx_aid(wl, wl->aid);
2165 if (ret < 0)
2166 goto out;
2167
2168 ret = wl1271_cmd_build_klv_null_data(wl);
2169 if (ret < 0)
2170 goto out;
2171
2172 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2173 ACX_KEEP_ALIVE_TPL_VALID);
2174 if (ret < 0)
2175 goto out;
2176
2177out:
2178 return ret;
2179}
2180
2181static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002182{
2183 int ret;
2184
2185 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002186 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002187 if (ret < 0)
2188 goto out;
2189
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002190 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002191
Oz Krakowskib992c682011-06-26 10:36:02 +03002192 /* reset TX security counters on a clean disconnect */
2193 wl->tx_security_last_seq_lsb = 0;
2194 wl->tx_security_seq = 0;
2195
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002196out:
2197 return ret;
2198}
2199
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002200static void wl1271_set_band_rate(struct wl1271 *wl)
2201{
2202 if (wl->band == IEEE80211_BAND_2GHZ)
2203 wl->basic_rate_set = wl->conf.tx.basic_rate;
2204 else
2205 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2206}
2207
Eliad Peller251c1772011-08-14 13:17:17 +03002208static bool wl12xx_is_roc(struct wl1271 *wl)
2209{
2210 u8 role_id;
2211
2212 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2213 if (role_id >= WL12XX_MAX_ROLES)
2214 return false;
2215
2216 return true;
2217}
2218
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002219static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002220{
2221 int ret;
2222
2223 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002224 /* no need to croc if we weren't busy (e.g. during boot) */
2225 if (wl12xx_is_roc(wl)) {
2226 ret = wl12xx_croc(wl, wl->dev_role_id);
2227 if (ret < 0)
2228 goto out;
2229
2230 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002231 if (ret < 0)
2232 goto out;
2233 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002234 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002235 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002236 if (ret < 0)
2237 goto out;
2238 ret = wl1271_acx_keep_alive_config(
2239 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2240 ACX_KEEP_ALIVE_TPL_INVALID);
2241 if (ret < 0)
2242 goto out;
2243 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2244 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002245 /* The current firmware only supports sched_scan in idle */
2246 if (wl->sched_scanning) {
2247 wl1271_scan_sched_scan_stop(wl);
2248 ieee80211_sched_scan_stopped(wl->hw);
2249 }
2250
Eliad Peller251c1772011-08-14 13:17:17 +03002251 ret = wl12xx_cmd_role_start_dev(wl);
2252 if (ret < 0)
2253 goto out;
2254
2255 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002256 if (ret < 0)
2257 goto out;
2258 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2259 }
2260
2261out:
2262 return ret;
2263}
2264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002265static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2266{
2267 struct wl1271 *wl = hw->priv;
2268 struct ieee80211_conf *conf = &hw->conf;
2269 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002270 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271
2272 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2273
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002274 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2275 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276 channel,
2277 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002278 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002279 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2280 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002282 /*
2283 * mac80211 will go to idle nearly immediately after transmitting some
2284 * frames, such as the deauth. To make sure those frames reach the air,
2285 * wait here until the TX queue is fully flushed.
2286 */
2287 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2288 (conf->flags & IEEE80211_CONF_IDLE))
2289 wl1271_tx_flush(wl);
2290
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291 mutex_lock(&wl->mutex);
2292
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002293 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002294 /* we support configuring the channel and band while off */
2295 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2296 wl->band = conf->channel->band;
2297 wl->channel = channel;
2298 }
2299
Arik Nemtsov097f8822011-06-27 22:06:34 +03002300 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2301 wl->power_level = conf->power_level;
2302
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002303 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002304 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002305
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002306 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2307
Ido Yariva6208652011-03-01 15:14:41 +02002308 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002309 if (ret < 0)
2310 goto out;
2311
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002312 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002313 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2314 ((wl->band != conf->channel->band) ||
2315 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002316 wl->band = conf->channel->band;
2317 wl->channel = channel;
2318
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002319 if (!is_ap) {
2320 /*
2321 * FIXME: the mac80211 should really provide a fixed
2322 * rate to use here. for now, just use the smallest
2323 * possible rate for the band as a fixed rate for
2324 * association frames and other control messages.
2325 */
2326 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2327 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002328
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002329 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2330 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002331 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002332 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002334
Eliad Peller251c1772011-08-14 13:17:17 +03002335 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2336 if (wl12xx_is_roc(wl)) {
2337 /* roaming */
2338 ret = wl12xx_croc(wl, wl->dev_role_id);
2339 if (ret < 0)
2340 goto out_sleep;
2341 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002342 ret = wl1271_join(wl, false);
2343 if (ret < 0)
2344 wl1271_warning("cmd join on channel "
2345 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002346 } else {
2347 /*
2348 * change the ROC channel. do it only if we are
2349 * not idle. otherwise, CROC will be called
2350 * anyway.
2351 */
2352 if (wl12xx_is_roc(wl) &&
2353 !(conf->flags & IEEE80211_CONF_IDLE)) {
2354 ret = wl12xx_croc(wl, wl->dev_role_id);
2355 if (ret < 0)
2356 goto out_sleep;
2357
2358 ret = wl12xx_roc(wl, wl->dev_role_id);
2359 if (ret < 0)
2360 wl1271_warning("roc failed %d",
2361 ret);
2362 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002363 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002364 }
2365 }
2366
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002367 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2368 ret = wl1271_sta_handle_idle(wl,
2369 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002370 if (ret < 0)
2371 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 }
2373
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002374 /*
2375 * if mac80211 changes the PSM mode, make sure the mode is not
2376 * incorrectly changed after the pspoll failure active window.
2377 */
2378 if (changed & IEEE80211_CONF_CHANGE_PS)
2379 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2380
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002381 if (conf->flags & IEEE80211_CONF_PS &&
2382 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2383 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384
2385 /*
2386 * We enter PSM only if we're already associated.
2387 * If we're not, we'll enter it when joining an SSID,
2388 * through the bss_info_changed() hook.
2389 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002390 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002391 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002392 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002393 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002394 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002396 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002397 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002399 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002401 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002402 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002403 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404 }
2405
2406 if (conf->power_level != wl->power_level) {
2407 ret = wl1271_acx_tx_power(wl, conf->power_level);
2408 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002409 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002410
2411 wl->power_level = conf->power_level;
2412 }
2413
2414out_sleep:
2415 wl1271_ps_elp_sleep(wl);
2416
2417out:
2418 mutex_unlock(&wl->mutex);
2419
2420 return ret;
2421}
2422
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002423struct wl1271_filter_params {
2424 bool enabled;
2425 int mc_list_length;
2426 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2427};
2428
Jiri Pirko22bedad2010-04-01 21:22:57 +00002429static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2430 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002431{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002432 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002433 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002434 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002435
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002436 if (unlikely(wl->state == WL1271_STATE_OFF))
2437 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002438
Juuso Oikarinen74441132009-10-13 12:47:53 +03002439 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002440 if (!fp) {
2441 wl1271_error("Out of memory setting filters.");
2442 return 0;
2443 }
2444
2445 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002446 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002447 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2448 fp->enabled = false;
2449 } else {
2450 fp->enabled = true;
2451 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002452 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002453 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002454 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002455 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002456 }
2457
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002458 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002459}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002460
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002461#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2462 FIF_ALLMULTI | \
2463 FIF_FCSFAIL | \
2464 FIF_BCN_PRBRESP_PROMISC | \
2465 FIF_CONTROL | \
2466 FIF_OTHER_BSS)
2467
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2469 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002470 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002472 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002474 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475
Arik Nemtsov7d057862010-10-16 19:25:35 +02002476 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2477 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002479 mutex_lock(&wl->mutex);
2480
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002481 *total &= WL1271_SUPPORTED_FILTERS;
2482 changed &= WL1271_SUPPORTED_FILTERS;
2483
2484 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002485 goto out;
2486
Ido Yariva6208652011-03-01 15:14:41 +02002487 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002488 if (ret < 0)
2489 goto out;
2490
Arik Nemtsov7d057862010-10-16 19:25:35 +02002491 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2492 if (*total & FIF_ALLMULTI)
2493 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2494 else if (fp)
2495 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2496 fp->mc_list,
2497 fp->mc_list_length);
2498 if (ret < 0)
2499 goto out_sleep;
2500 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002501
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002502 /*
2503 * the fw doesn't provide an api to configure the filters. instead,
2504 * the filters configuration is based on the active roles / ROC
2505 * state.
2506 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002507
2508out_sleep:
2509 wl1271_ps_elp_sleep(wl);
2510
2511out:
2512 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002513 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002514}
2515
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002516static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2517 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2518 u16 tx_seq_16)
2519{
2520 struct wl1271_ap_key *ap_key;
2521 int i;
2522
2523 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2524
2525 if (key_size > MAX_KEY_SIZE)
2526 return -EINVAL;
2527
2528 /*
2529 * Find next free entry in ap_keys. Also check we are not replacing
2530 * an existing key.
2531 */
2532 for (i = 0; i < MAX_NUM_KEYS; i++) {
2533 if (wl->recorded_ap_keys[i] == NULL)
2534 break;
2535
2536 if (wl->recorded_ap_keys[i]->id == id) {
2537 wl1271_warning("trying to record key replacement");
2538 return -EINVAL;
2539 }
2540 }
2541
2542 if (i == MAX_NUM_KEYS)
2543 return -EBUSY;
2544
2545 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2546 if (!ap_key)
2547 return -ENOMEM;
2548
2549 ap_key->id = id;
2550 ap_key->key_type = key_type;
2551 ap_key->key_size = key_size;
2552 memcpy(ap_key->key, key, key_size);
2553 ap_key->hlid = hlid;
2554 ap_key->tx_seq_32 = tx_seq_32;
2555 ap_key->tx_seq_16 = tx_seq_16;
2556
2557 wl->recorded_ap_keys[i] = ap_key;
2558 return 0;
2559}
2560
2561static void wl1271_free_ap_keys(struct wl1271 *wl)
2562{
2563 int i;
2564
2565 for (i = 0; i < MAX_NUM_KEYS; i++) {
2566 kfree(wl->recorded_ap_keys[i]);
2567 wl->recorded_ap_keys[i] = NULL;
2568 }
2569}
2570
2571static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2572{
2573 int i, ret = 0;
2574 struct wl1271_ap_key *key;
2575 bool wep_key_added = false;
2576
2577 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002578 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002579 if (wl->recorded_ap_keys[i] == NULL)
2580 break;
2581
2582 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002583 hlid = key->hlid;
2584 if (hlid == WL12XX_INVALID_LINK_ID)
2585 hlid = wl->ap_bcast_hlid;
2586
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002587 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2588 key->id, key->key_type,
2589 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002590 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002591 key->tx_seq_16);
2592 if (ret < 0)
2593 goto out;
2594
2595 if (key->key_type == KEY_WEP)
2596 wep_key_added = true;
2597 }
2598
2599 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002600 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002601 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002602 if (ret < 0)
2603 goto out;
2604 }
2605
2606out:
2607 wl1271_free_ap_keys(wl);
2608 return ret;
2609}
2610
2611static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2612 u8 key_size, const u8 *key, u32 tx_seq_32,
2613 u16 tx_seq_16, struct ieee80211_sta *sta)
2614{
2615 int ret;
2616 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2617
2618 if (is_ap) {
2619 struct wl1271_station *wl_sta;
2620 u8 hlid;
2621
2622 if (sta) {
2623 wl_sta = (struct wl1271_station *)sta->drv_priv;
2624 hlid = wl_sta->hlid;
2625 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002626 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002627 }
2628
2629 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2630 /*
2631 * We do not support removing keys after AP shutdown.
2632 * Pretend we do to make mac80211 happy.
2633 */
2634 if (action != KEY_ADD_OR_REPLACE)
2635 return 0;
2636
2637 ret = wl1271_record_ap_key(wl, id,
2638 key_type, key_size,
2639 key, hlid, tx_seq_32,
2640 tx_seq_16);
2641 } else {
2642 ret = wl1271_cmd_set_ap_key(wl, action,
2643 id, key_type, key_size,
2644 key, hlid, tx_seq_32,
2645 tx_seq_16);
2646 }
2647
2648 if (ret < 0)
2649 return ret;
2650 } else {
2651 const u8 *addr;
2652 static const u8 bcast_addr[ETH_ALEN] = {
2653 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2654 };
2655
2656 addr = sta ? sta->addr : bcast_addr;
2657
2658 if (is_zero_ether_addr(addr)) {
2659 /* We dont support TX only encryption */
2660 return -EOPNOTSUPP;
2661 }
2662
2663 /* The wl1271 does not allow to remove unicast keys - they
2664 will be cleared automatically on next CMD_JOIN. Ignore the
2665 request silently, as we dont want the mac80211 to emit
2666 an error message. */
2667 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2668 return 0;
2669
Eliad Peller010d3d32011-08-14 13:17:31 +03002670 /* don't remove key if hlid was already deleted */
2671 if (action == KEY_REMOVE &&
2672 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2673 return 0;
2674
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002675 ret = wl1271_cmd_set_sta_key(wl, action,
2676 id, key_type, key_size,
2677 key, addr, tx_seq_32,
2678 tx_seq_16);
2679 if (ret < 0)
2680 return ret;
2681
2682 /* the default WEP key needs to be configured at least once */
2683 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002684 ret = wl12xx_cmd_set_default_wep_key(wl,
2685 wl->default_key,
2686 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002687 if (ret < 0)
2688 return ret;
2689 }
2690 }
2691
2692 return 0;
2693}
2694
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002695static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2696 struct ieee80211_vif *vif,
2697 struct ieee80211_sta *sta,
2698 struct ieee80211_key_conf *key_conf)
2699{
2700 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002702 u32 tx_seq_32 = 0;
2703 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704 u8 key_type;
2705
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2707
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002708 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002710 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002711 key_conf->keylen, key_conf->flags);
2712 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2713
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002714 mutex_lock(&wl->mutex);
2715
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002716 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2717 ret = -EAGAIN;
2718 goto out_unlock;
2719 }
2720
Ido Yariva6208652011-03-01 15:14:41 +02002721 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722 if (ret < 0)
2723 goto out_unlock;
2724
Johannes Berg97359d12010-08-10 09:46:38 +02002725 switch (key_conf->cipher) {
2726 case WLAN_CIPHER_SUITE_WEP40:
2727 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 key_type = KEY_WEP;
2729
2730 key_conf->hw_key_idx = key_conf->keyidx;
2731 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002732 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733 key_type = KEY_TKIP;
2734
2735 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002736 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2737 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002739 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 key_type = KEY_AES;
2741
2742 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002743 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2744 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002745 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002746 case WL1271_CIPHER_SUITE_GEM:
2747 key_type = KEY_GEM;
2748 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2749 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2750 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002751 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002752 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002753
2754 ret = -EOPNOTSUPP;
2755 goto out_sleep;
2756 }
2757
2758 switch (cmd) {
2759 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002760 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2761 key_conf->keyidx, key_type,
2762 key_conf->keylen, key_conf->key,
2763 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002764 if (ret < 0) {
2765 wl1271_error("Could not add or replace key");
2766 goto out_sleep;
2767 }
2768 break;
2769
2770 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 ret = wl1271_set_key(wl, KEY_REMOVE,
2772 key_conf->keyidx, key_type,
2773 key_conf->keylen, key_conf->key,
2774 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002775 if (ret < 0) {
2776 wl1271_error("Could not remove key");
2777 goto out_sleep;
2778 }
2779 break;
2780
2781 default:
2782 wl1271_error("Unsupported key cmd 0x%x", cmd);
2783 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002784 break;
2785 }
2786
2787out_sleep:
2788 wl1271_ps_elp_sleep(wl);
2789
2790out_unlock:
2791 mutex_unlock(&wl->mutex);
2792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 return ret;
2794}
2795
2796static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002797 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 struct cfg80211_scan_request *req)
2799{
2800 struct wl1271 *wl = hw->priv;
2801 int ret;
2802 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002803 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804
2805 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2806
2807 if (req->n_ssids) {
2808 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002809 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002810 }
2811
2812 mutex_lock(&wl->mutex);
2813
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002814 if (wl->state == WL1271_STATE_OFF) {
2815 /*
2816 * We cannot return -EBUSY here because cfg80211 will expect
2817 * a call to ieee80211_scan_completed if we do - in this case
2818 * there won't be any call.
2819 */
2820 ret = -EAGAIN;
2821 goto out;
2822 }
2823
Ido Yariva6208652011-03-01 15:14:41 +02002824 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 if (ret < 0)
2826 goto out;
2827
Eliad Peller251c1772011-08-14 13:17:17 +03002828 /* cancel ROC before scanning */
2829 if (wl12xx_is_roc(wl)) {
2830 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2831 /* don't allow scanning right now */
2832 ret = -EBUSY;
2833 goto out_sleep;
2834 }
2835 wl12xx_croc(wl, wl->dev_role_id);
2836 wl12xx_cmd_role_stop_dev(wl);
2837 }
2838
Luciano Coelho5924f892010-08-04 03:46:22 +03002839 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002840out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002842out:
2843 mutex_unlock(&wl->mutex);
2844
2845 return ret;
2846}
2847
Eliad Peller73ecce32011-06-27 13:06:45 +03002848static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2849 struct ieee80211_vif *vif)
2850{
2851 struct wl1271 *wl = hw->priv;
2852 int ret;
2853
2854 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2855
2856 mutex_lock(&wl->mutex);
2857
2858 if (wl->state == WL1271_STATE_OFF)
2859 goto out;
2860
2861 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2862 goto out;
2863
2864 ret = wl1271_ps_elp_wakeup(wl);
2865 if (ret < 0)
2866 goto out;
2867
2868 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2869 ret = wl1271_scan_stop(wl);
2870 if (ret < 0)
2871 goto out_sleep;
2872 }
2873 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2874 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2875 wl->scan.req = NULL;
2876 ieee80211_scan_completed(wl->hw, true);
2877
2878out_sleep:
2879 wl1271_ps_elp_sleep(wl);
2880out:
2881 mutex_unlock(&wl->mutex);
2882
2883 cancel_delayed_work_sync(&wl->scan_complete_work);
2884}
2885
Luciano Coelho33c2c062011-05-10 14:46:02 +03002886static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2887 struct ieee80211_vif *vif,
2888 struct cfg80211_sched_scan_request *req,
2889 struct ieee80211_sched_scan_ies *ies)
2890{
2891 struct wl1271 *wl = hw->priv;
2892 int ret;
2893
2894 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2895
2896 mutex_lock(&wl->mutex);
2897
2898 ret = wl1271_ps_elp_wakeup(wl);
2899 if (ret < 0)
2900 goto out;
2901
2902 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2903 if (ret < 0)
2904 goto out_sleep;
2905
2906 ret = wl1271_scan_sched_scan_start(wl);
2907 if (ret < 0)
2908 goto out_sleep;
2909
2910 wl->sched_scanning = true;
2911
2912out_sleep:
2913 wl1271_ps_elp_sleep(wl);
2914out:
2915 mutex_unlock(&wl->mutex);
2916 return ret;
2917}
2918
2919static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2920 struct ieee80211_vif *vif)
2921{
2922 struct wl1271 *wl = hw->priv;
2923 int ret;
2924
2925 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2926
2927 mutex_lock(&wl->mutex);
2928
2929 ret = wl1271_ps_elp_wakeup(wl);
2930 if (ret < 0)
2931 goto out;
2932
2933 wl1271_scan_sched_scan_stop(wl);
2934
2935 wl1271_ps_elp_sleep(wl);
2936out:
2937 mutex_unlock(&wl->mutex);
2938}
2939
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002940static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2941{
2942 struct wl1271 *wl = hw->priv;
2943 int ret = 0;
2944
2945 mutex_lock(&wl->mutex);
2946
2947 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2948 ret = -EAGAIN;
2949 goto out;
2950 }
2951
Ido Yariva6208652011-03-01 15:14:41 +02002952 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002953 if (ret < 0)
2954 goto out;
2955
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002956 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002957 if (ret < 0)
2958 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2959
2960 wl1271_ps_elp_sleep(wl);
2961
2962out:
2963 mutex_unlock(&wl->mutex);
2964
2965 return ret;
2966}
2967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2969{
2970 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002971 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972
2973 mutex_lock(&wl->mutex);
2974
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002975 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2976 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002977 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002978 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002979
Ido Yariva6208652011-03-01 15:14:41 +02002980 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 if (ret < 0)
2982 goto out;
2983
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002984 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985 if (ret < 0)
2986 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2987
2988 wl1271_ps_elp_sleep(wl);
2989
2990out:
2991 mutex_unlock(&wl->mutex);
2992
2993 return ret;
2994}
2995
Arik Nemtsove78a2872010-10-16 19:07:21 +02002996static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002997 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002998{
Eliad Peller889cb362011-05-01 09:56:45 +03002999 u8 ssid_len;
3000 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3001 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003002
Eliad Peller889cb362011-05-01 09:56:45 +03003003 if (!ptr) {
3004 wl1271_error("No SSID in IEs!");
3005 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003006 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003007
Eliad Peller889cb362011-05-01 09:56:45 +03003008 ssid_len = ptr[1];
3009 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3010 wl1271_error("SSID is too long!");
3011 return -EINVAL;
3012 }
3013
3014 wl->ssid_len = ssid_len;
3015 memcpy(wl->ssid, ptr+2, ssid_len);
3016 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003017}
3018
Arik Nemtsove78a2872010-10-16 19:07:21 +02003019static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3020 struct ieee80211_bss_conf *bss_conf,
3021 u32 changed)
3022{
3023 int ret = 0;
3024
3025 if (changed & BSS_CHANGED_ERP_SLOT) {
3026 if (bss_conf->use_short_slot)
3027 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3028 else
3029 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3030 if (ret < 0) {
3031 wl1271_warning("Set slot time failed %d", ret);
3032 goto out;
3033 }
3034 }
3035
3036 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3037 if (bss_conf->use_short_preamble)
3038 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3039 else
3040 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3041 }
3042
3043 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3044 if (bss_conf->use_cts_prot)
3045 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3046 else
3047 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3048 if (ret < 0) {
3049 wl1271_warning("Set ctsprotect failed %d", ret);
3050 goto out;
3051 }
3052 }
3053
3054out:
3055 return ret;
3056}
3057
3058static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3059 struct ieee80211_vif *vif,
3060 struct ieee80211_bss_conf *bss_conf,
3061 u32 changed)
3062{
3063 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3064 int ret = 0;
3065
3066 if ((changed & BSS_CHANGED_BEACON_INT)) {
3067 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3068 bss_conf->beacon_int);
3069
3070 wl->beacon_int = bss_conf->beacon_int;
3071 }
3072
3073 if ((changed & BSS_CHANGED_BEACON)) {
3074 struct ieee80211_hdr *hdr;
3075 int ieoffset = offsetof(struct ieee80211_mgmt,
3076 u.beacon.variable);
3077 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3078 u16 tmpl_id;
3079
3080 if (!beacon)
3081 goto out;
3082
3083 wl1271_debug(DEBUG_MASTER, "beacon updated");
3084
3085 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3086 if (ret < 0) {
3087 dev_kfree_skb(beacon);
3088 goto out;
3089 }
3090 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3091 CMD_TEMPL_BEACON;
3092 ret = wl1271_cmd_template_set(wl, tmpl_id,
3093 beacon->data,
3094 beacon->len, 0,
3095 wl1271_tx_min_rate_get(wl));
3096 if (ret < 0) {
3097 dev_kfree_skb(beacon);
3098 goto out;
3099 }
3100
3101 hdr = (struct ieee80211_hdr *) beacon->data;
3102 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3103 IEEE80211_STYPE_PROBE_RESP);
3104
3105 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3106 CMD_TEMPL_PROBE_RESPONSE;
3107 ret = wl1271_cmd_template_set(wl,
3108 tmpl_id,
3109 beacon->data,
3110 beacon->len, 0,
3111 wl1271_tx_min_rate_get(wl));
3112 dev_kfree_skb(beacon);
3113 if (ret < 0)
3114 goto out;
3115 }
3116
3117out:
3118 return ret;
3119}
3120
3121/* AP mode changes */
3122static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 struct ieee80211_vif *vif,
3124 struct ieee80211_bss_conf *bss_conf,
3125 u32 changed)
3126{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003127 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003128
Arik Nemtsove78a2872010-10-16 19:07:21 +02003129 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3130 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131
Arik Nemtsove78a2872010-10-16 19:07:21 +02003132 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3133 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003134
Arik Nemtsov70f47422011-04-18 14:15:25 +03003135 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003136 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003137 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003138 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003139 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003140
3141 ret = wl1271_ap_init_templates(wl);
3142 if (ret < 0)
3143 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003144 }
3145
Arik Nemtsove78a2872010-10-16 19:07:21 +02003146 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3147 if (ret < 0)
3148 goto out;
3149
3150 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3151 if (bss_conf->enable_beacon) {
3152 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003153 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003154 if (ret < 0)
3155 goto out;
3156
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003157 ret = wl1271_ap_init_hwenc(wl);
3158 if (ret < 0)
3159 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003160
3161 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3162 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003163 }
3164 } else {
3165 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003166 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003167 if (ret < 0)
3168 goto out;
3169
3170 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3171 wl1271_debug(DEBUG_AP, "stopped AP");
3172 }
3173 }
3174 }
3175
3176 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3177 if (ret < 0)
3178 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003179
3180 /* Handle HT information change */
3181 if ((changed & BSS_CHANGED_HT) &&
3182 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3183 ret = wl1271_acx_set_ht_information(wl,
3184 bss_conf->ht_operation_mode);
3185 if (ret < 0) {
3186 wl1271_warning("Set ht information failed %d", ret);
3187 goto out;
3188 }
3189 }
3190
Arik Nemtsove78a2872010-10-16 19:07:21 +02003191out:
3192 return;
3193}
3194
3195/* STA/IBSS mode changes */
3196static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3197 struct ieee80211_vif *vif,
3198 struct ieee80211_bss_conf *bss_conf,
3199 u32 changed)
3200{
3201 bool do_join = false, set_assoc = false;
3202 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003203 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003204 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003205 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003206 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003207 bool sta_exists = false;
3208 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003209
3210 if (is_ibss) {
3211 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3212 changed);
3213 if (ret < 0)
3214 goto out;
3215 }
3216
Eliad Peller227e81e2011-08-14 13:17:26 +03003217 if (changed & BSS_CHANGED_IBSS) {
3218 if (bss_conf->ibss_joined) {
3219 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3220 ibss_joined = true;
3221 } else {
3222 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3223 &wl->flags)) {
3224 wl1271_unjoin(wl);
3225 wl12xx_cmd_role_start_dev(wl);
3226 wl12xx_roc(wl, wl->dev_role_id);
3227 }
3228 }
3229 }
3230
3231 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003232 do_join = true;
3233
3234 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003235 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003236 do_join = true;
3237
Eliad Peller227e81e2011-08-14 13:17:26 +03003238 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003239 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3240 bss_conf->enable_beacon ? "enabled" : "disabled");
3241
3242 if (bss_conf->enable_beacon)
3243 wl->set_bss_type = BSS_TYPE_IBSS;
3244 else
3245 wl->set_bss_type = BSS_TYPE_STA_BSS;
3246 do_join = true;
3247 }
3248
Arik Nemtsove78a2872010-10-16 19:07:21 +02003249 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003250 bool enable = false;
3251 if (bss_conf->cqm_rssi_thold)
3252 enable = true;
3253 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3254 bss_conf->cqm_rssi_thold,
3255 bss_conf->cqm_rssi_hyst);
3256 if (ret < 0)
3257 goto out;
3258 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3259 }
3260
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003261 if ((changed & BSS_CHANGED_BSSID) &&
3262 /*
3263 * Now we know the correct bssid, so we send a new join command
3264 * and enable the BSSID filter
3265 */
3266 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003267 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003268
Eliad Pellerfa287b82010-12-26 09:27:50 +01003269 if (!is_zero_ether_addr(wl->bssid)) {
3270 ret = wl1271_cmd_build_null_data(wl);
3271 if (ret < 0)
3272 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003273
Eliad Pellerfa287b82010-12-26 09:27:50 +01003274 ret = wl1271_build_qos_null_data(wl);
3275 if (ret < 0)
3276 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003277
Eliad Pellerfa287b82010-12-26 09:27:50 +01003278 /* Need to update the BSSID (for filtering etc) */
3279 do_join = true;
3280 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003281 }
3282
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003283 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3284 rcu_read_lock();
3285 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3286 if (!sta)
3287 goto sta_not_found;
3288
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003289 /* save the supp_rates of the ap */
3290 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3291 if (sta->ht_cap.ht_supported)
3292 sta_rate_set |=
3293 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003294 sta_ht_cap = sta->ht_cap;
3295 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003296
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003297sta_not_found:
3298 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003299 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003300
Arik Nemtsove78a2872010-10-16 19:07:21 +02003301 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003303 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003304 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003306 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003308 wl->ps_poll_failures = 0;
3309
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003310 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003311 * use basic rates from AP, and determine lowest rate
3312 * to use with control frames.
3313 */
3314 rates = bss_conf->basic_rates;
3315 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3316 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003317 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003318 if (sta_rate_set)
3319 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3320 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003321 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003322 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003323 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003324
3325 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003326 * with wl1271, we don't need to update the
3327 * beacon_int and dtim_period, because the firmware
3328 * updates it by itself when the first beacon is
3329 * received after a join.
3330 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3332 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003334
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003335 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003336 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003337 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003338 dev_kfree_skb(wl->probereq);
3339 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3340 ieoffset = offsetof(struct ieee80211_mgmt,
3341 u.probe_req.variable);
3342 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003343
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003344 /* enable the connection monitoring feature */
3345 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003347 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003348
3349 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003350 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3351 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352 enum wl1271_cmd_ps_mode mode;
3353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003354 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003355 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003356 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003357 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003358 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003359 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003360 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003361 } else {
3362 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003363 bool was_assoc =
3364 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3365 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003366 bool was_ifup =
3367 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3368 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003369 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003370
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003371 /* free probe-request template */
3372 dev_kfree_skb(wl->probereq);
3373 wl->probereq = NULL;
3374
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003375 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003376 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003377
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003378 /* revert back to minimum rates for the current band */
3379 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003380 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003381 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003382 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003383 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003384
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003385 /* disable connection monitor features */
3386 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003387
3388 /* Disable the keep-alive feature */
3389 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003390 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003392
3393 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003394 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003395 u32 conf_flags = wl->hw->conf.flags;
3396 /*
3397 * we might have to disable roc, if there was
3398 * no IF_OPER_UP notification.
3399 */
3400 if (!was_ifup) {
3401 ret = wl12xx_croc(wl, wl->role_id);
3402 if (ret < 0)
3403 goto out;
3404 }
3405 /*
3406 * (we also need to disable roc in case of
3407 * roaming on the same channel. until we will
3408 * have a better flow...)
3409 */
3410 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3411 ret = wl12xx_croc(wl, wl->dev_role_id);
3412 if (ret < 0)
3413 goto out;
3414 }
3415
Eliad Peller30df14d2011-04-05 19:13:28 +03003416 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003417 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3418 wl12xx_cmd_role_start_dev(wl);
3419 wl12xx_roc(wl, wl->dev_role_id);
3420 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003421 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003422 }
3423 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003424
Eliad Pellerd192d262011-05-24 14:33:08 +03003425 if (changed & BSS_CHANGED_IBSS) {
3426 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3427 bss_conf->ibss_joined);
3428
3429 if (bss_conf->ibss_joined) {
3430 u32 rates = bss_conf->basic_rates;
3431 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3432 rates);
3433 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3434
3435 /* by default, use 11b rates */
3436 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3437 ret = wl1271_acx_sta_rate_policies(wl);
3438 if (ret < 0)
3439 goto out;
3440 }
3441 }
3442
Arik Nemtsove78a2872010-10-16 19:07:21 +02003443 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3444 if (ret < 0)
3445 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003447 if (changed & BSS_CHANGED_ARP_FILTER) {
3448 __be32 addr = bss_conf->arp_addr_list[0];
3449 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3450
Eliad Pellerc5312772010-12-09 11:31:27 +02003451 if (bss_conf->arp_addr_cnt == 1 &&
3452 bss_conf->arp_filter_enabled) {
3453 /*
3454 * The template should have been configured only upon
3455 * association. however, it seems that the correct ip
3456 * isn't being set (when sending), so we have to
3457 * reconfigure the template upon every ip change.
3458 */
3459 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3460 if (ret < 0) {
3461 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003462 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003463 }
3464
3465 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003466 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003467 addr);
3468 } else
3469 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003470
3471 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003472 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003473 }
3474
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003475 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003476 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003477 if (ret < 0) {
3478 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003479 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003480 }
Eliad Peller251c1772011-08-14 13:17:17 +03003481
3482 /* ROC until connected (after EAPOL exchange) */
3483 if (!is_ibss) {
3484 ret = wl12xx_roc(wl, wl->role_id);
3485 if (ret < 0)
3486 goto out;
3487
3488 wl1271_check_operstate(wl,
3489 ieee80211_get_operstate(vif));
3490 }
3491 /*
3492 * stop device role if started (we might already be in
3493 * STA role). TODO: make it better.
3494 */
3495 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3496 ret = wl12xx_croc(wl, wl->dev_role_id);
3497 if (ret < 0)
3498 goto out;
3499
3500 ret = wl12xx_cmd_role_stop_dev(wl);
3501 if (ret < 0)
3502 goto out;
3503 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003504 }
3505
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003506 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003507 if (sta_exists) {
3508 if ((changed & BSS_CHANGED_HT) &&
3509 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003510 ret = wl1271_acx_set_ht_capabilities(wl,
3511 &sta_ht_cap,
3512 true,
3513 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003514 if (ret < 0) {
3515 wl1271_warning("Set ht cap true failed %d",
3516 ret);
3517 goto out;
3518 }
3519 }
3520 /* handle new association without HT and disassociation */
3521 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003522 ret = wl1271_acx_set_ht_capabilities(wl,
3523 &sta_ht_cap,
3524 false,
3525 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003526 if (ret < 0) {
3527 wl1271_warning("Set ht cap false failed %d",
3528 ret);
3529 goto out;
3530 }
3531 }
3532 }
3533
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003534 /* Handle HT information change. Done after join. */
3535 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003536 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3537 ret = wl1271_acx_set_ht_information(wl,
3538 bss_conf->ht_operation_mode);
3539 if (ret < 0) {
3540 wl1271_warning("Set ht information failed %d", ret);
3541 goto out;
3542 }
3543 }
3544
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545out:
3546 return;
3547}
3548
3549static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3550 struct ieee80211_vif *vif,
3551 struct ieee80211_bss_conf *bss_conf,
3552 u32 changed)
3553{
3554 struct wl1271 *wl = hw->priv;
3555 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3556 int ret;
3557
3558 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3559 (int)changed);
3560
3561 mutex_lock(&wl->mutex);
3562
3563 if (unlikely(wl->state == WL1271_STATE_OFF))
3564 goto out;
3565
Ido Yariva6208652011-03-01 15:14:41 +02003566 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 if (ret < 0)
3568 goto out;
3569
3570 if (is_ap)
3571 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3572 else
3573 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003575 wl1271_ps_elp_sleep(wl);
3576
3577out:
3578 mutex_unlock(&wl->mutex);
3579}
3580
Kalle Valoc6999d82010-02-18 13:25:41 +02003581static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3582 const struct ieee80211_tx_queue_params *params)
3583{
3584 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003585 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003586 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003587
3588 mutex_lock(&wl->mutex);
3589
3590 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3591
Kalle Valo4695dc92010-03-18 12:26:38 +02003592 if (params->uapsd)
3593 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3594 else
3595 ps_scheme = CONF_PS_SCHEME_LEGACY;
3596
Arik Nemtsov488fc542010-10-16 20:33:45 +02003597 if (wl->state == WL1271_STATE_OFF) {
3598 /*
3599 * If the state is off, the parameters will be recorded and
3600 * configured on init. This happens in AP-mode.
3601 */
3602 struct conf_tx_ac_category *conf_ac =
3603 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3604 struct conf_tx_tid *conf_tid =
3605 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3606
3607 conf_ac->ac = wl1271_tx_get_queue(queue);
3608 conf_ac->cw_min = (u8)params->cw_min;
3609 conf_ac->cw_max = params->cw_max;
3610 conf_ac->aifsn = params->aifs;
3611 conf_ac->tx_op_limit = params->txop << 5;
3612
3613 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3614 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3615 conf_tid->tsid = wl1271_tx_get_queue(queue);
3616 conf_tid->ps_scheme = ps_scheme;
3617 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3618 conf_tid->apsd_conf[0] = 0;
3619 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003620 goto out;
3621 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003622
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003623 ret = wl1271_ps_elp_wakeup(wl);
3624 if (ret < 0)
3625 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003626
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003627 /*
3628 * the txop is confed in units of 32us by the mac80211,
3629 * we need us
3630 */
3631 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3632 params->cw_min, params->cw_max,
3633 params->aifs, params->txop << 5);
3634 if (ret < 0)
3635 goto out_sleep;
3636
3637 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3638 CONF_CHANNEL_TYPE_EDCF,
3639 wl1271_tx_get_queue(queue),
3640 ps_scheme, CONF_ACK_POLICY_LEGACY,
3641 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003642
3643out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003644 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003645
3646out:
3647 mutex_unlock(&wl->mutex);
3648
3649 return ret;
3650}
3651
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003652static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3653{
3654
3655 struct wl1271 *wl = hw->priv;
3656 u64 mactime = ULLONG_MAX;
3657 int ret;
3658
3659 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3660
3661 mutex_lock(&wl->mutex);
3662
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003663 if (unlikely(wl->state == WL1271_STATE_OFF))
3664 goto out;
3665
Ido Yariva6208652011-03-01 15:14:41 +02003666 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003667 if (ret < 0)
3668 goto out;
3669
3670 ret = wl1271_acx_tsf_info(wl, &mactime);
3671 if (ret < 0)
3672 goto out_sleep;
3673
3674out_sleep:
3675 wl1271_ps_elp_sleep(wl);
3676
3677out:
3678 mutex_unlock(&wl->mutex);
3679 return mactime;
3680}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003681
John W. Linvilleece550d2010-07-28 16:41:06 -04003682static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3683 struct survey_info *survey)
3684{
3685 struct wl1271 *wl = hw->priv;
3686 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003687
John W. Linvilleece550d2010-07-28 16:41:06 -04003688 if (idx != 0)
3689 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003690
John W. Linvilleece550d2010-07-28 16:41:06 -04003691 survey->channel = conf->channel;
3692 survey->filled = SURVEY_INFO_NOISE_DBM;
3693 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003694
John W. Linvilleece550d2010-07-28 16:41:06 -04003695 return 0;
3696}
3697
Arik Nemtsov409622e2011-02-23 00:22:29 +02003698static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003699 struct ieee80211_sta *sta,
3700 u8 *hlid)
3701{
3702 struct wl1271_station *wl_sta;
3703 int id;
3704
3705 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3706 if (id >= AP_MAX_STATIONS) {
3707 wl1271_warning("could not allocate HLID - too much stations");
3708 return -EBUSY;
3709 }
3710
3711 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003712 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003713 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3714 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003715 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003716 return 0;
3717}
3718
Arik Nemtsov409622e2011-02-23 00:22:29 +02003719static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003720{
3721 int id = hlid - WL1271_AP_STA_HLID_START;
3722
Arik Nemtsov409622e2011-02-23 00:22:29 +02003723 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3724 return;
3725
Arik Nemtsov04216da2011-08-14 13:17:38 +03003726 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003727 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003728 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003729 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003730 __clear_bit(hlid, &wl->ap_ps_map);
3731 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003732}
3733
3734static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3735 struct ieee80211_vif *vif,
3736 struct ieee80211_sta *sta)
3737{
3738 struct wl1271 *wl = hw->priv;
3739 int ret = 0;
3740 u8 hlid;
3741
3742 mutex_lock(&wl->mutex);
3743
3744 if (unlikely(wl->state == WL1271_STATE_OFF))
3745 goto out;
3746
3747 if (wl->bss_type != BSS_TYPE_AP_BSS)
3748 goto out;
3749
3750 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3751
Arik Nemtsov409622e2011-02-23 00:22:29 +02003752 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003753 if (ret < 0)
3754 goto out;
3755
Ido Yariva6208652011-03-01 15:14:41 +02003756 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003757 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003758 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003759
Eliad Pellerc690ec82011-08-14 13:17:07 +03003760 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003761 if (ret < 0)
3762 goto out_sleep;
3763
Eliad Pellerb67476e2011-08-14 13:17:23 +03003764 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3765 if (ret < 0)
3766 goto out_sleep;
3767
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003768 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3769 if (ret < 0)
3770 goto out_sleep;
3771
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003772out_sleep:
3773 wl1271_ps_elp_sleep(wl);
3774
Arik Nemtsov409622e2011-02-23 00:22:29 +02003775out_free_sta:
3776 if (ret < 0)
3777 wl1271_free_sta(wl, hlid);
3778
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003779out:
3780 mutex_unlock(&wl->mutex);
3781 return ret;
3782}
3783
3784static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3785 struct ieee80211_vif *vif,
3786 struct ieee80211_sta *sta)
3787{
3788 struct wl1271 *wl = hw->priv;
3789 struct wl1271_station *wl_sta;
3790 int ret = 0, id;
3791
3792 mutex_lock(&wl->mutex);
3793
3794 if (unlikely(wl->state == WL1271_STATE_OFF))
3795 goto out;
3796
3797 if (wl->bss_type != BSS_TYPE_AP_BSS)
3798 goto out;
3799
3800 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3801
3802 wl_sta = (struct wl1271_station *)sta->drv_priv;
3803 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3804 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3805 goto out;
3806
Ido Yariva6208652011-03-01 15:14:41 +02003807 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003808 if (ret < 0)
3809 goto out;
3810
Eliad Pellerc690ec82011-08-14 13:17:07 +03003811 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003812 if (ret < 0)
3813 goto out_sleep;
3814
Arik Nemtsov409622e2011-02-23 00:22:29 +02003815 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003816
3817out_sleep:
3818 wl1271_ps_elp_sleep(wl);
3819
3820out:
3821 mutex_unlock(&wl->mutex);
3822 return ret;
3823}
3824
Luciano Coelho4623ec72011-03-21 19:26:41 +02003825static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3826 struct ieee80211_vif *vif,
3827 enum ieee80211_ampdu_mlme_action action,
3828 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3829 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003830{
3831 struct wl1271 *wl = hw->priv;
3832 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003833 u8 hlid, *ba_bitmap;
3834
3835 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3836 tid);
3837
3838 /* sanity check - the fields in FW are only 8bits wide */
3839 if (WARN_ON(tid > 0xFF))
3840 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003841
3842 mutex_lock(&wl->mutex);
3843
3844 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3845 ret = -EAGAIN;
3846 goto out;
3847 }
3848
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003849 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3850 hlid = wl->sta_hlid;
3851 ba_bitmap = &wl->ba_rx_bitmap;
3852 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3853 struct wl1271_station *wl_sta;
3854
3855 wl_sta = (struct wl1271_station *)sta->drv_priv;
3856 hlid = wl_sta->hlid;
3857 ba_bitmap = &wl->links[hlid].ba_bitmap;
3858 } else {
3859 ret = -EINVAL;
3860 goto out;
3861 }
3862
Ido Yariva6208652011-03-01 15:14:41 +02003863 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003864 if (ret < 0)
3865 goto out;
3866
Shahar Levi70559a02011-05-22 16:10:22 +03003867 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3868 tid, action);
3869
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003870 switch (action) {
3871 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003872 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003873 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003874 break;
3875 }
3876
3877 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3878 ret = -EBUSY;
3879 wl1271_error("exceeded max RX BA sessions");
3880 break;
3881 }
3882
3883 if (*ba_bitmap & BIT(tid)) {
3884 ret = -EINVAL;
3885 wl1271_error("cannot enable RX BA session on active "
3886 "tid: %d", tid);
3887 break;
3888 }
3889
3890 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3891 hlid);
3892 if (!ret) {
3893 *ba_bitmap |= BIT(tid);
3894 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003895 }
3896 break;
3897
3898 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003899 if (!(*ba_bitmap & BIT(tid))) {
3900 ret = -EINVAL;
3901 wl1271_error("no active RX BA session on tid: %d",
3902 tid);
3903 break;
3904 }
3905
3906 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3907 hlid);
3908 if (!ret) {
3909 *ba_bitmap &= ~BIT(tid);
3910 wl->ba_rx_session_count--;
3911 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003912 break;
3913
3914 /*
3915 * The BA initiator session management in FW independently.
3916 * Falling break here on purpose for all TX APDU commands.
3917 */
3918 case IEEE80211_AMPDU_TX_START:
3919 case IEEE80211_AMPDU_TX_STOP:
3920 case IEEE80211_AMPDU_TX_OPERATIONAL:
3921 ret = -EINVAL;
3922 break;
3923
3924 default:
3925 wl1271_error("Incorrect ampdu action id=%x\n", action);
3926 ret = -EINVAL;
3927 }
3928
3929 wl1271_ps_elp_sleep(wl);
3930
3931out:
3932 mutex_unlock(&wl->mutex);
3933
3934 return ret;
3935}
3936
Arik Nemtsov33437892011-04-26 23:35:39 +03003937static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3938{
3939 struct wl1271 *wl = hw->priv;
3940 bool ret = false;
3941
3942 mutex_lock(&wl->mutex);
3943
3944 if (unlikely(wl->state == WL1271_STATE_OFF))
3945 goto out;
3946
3947 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003948 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003949
3950 /* the above is appropriate for STA mode for PS purposes */
3951 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3952
3953out:
3954 mutex_unlock(&wl->mutex);
3955
3956 return ret;
3957}
3958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003959/* can't be const, mac80211 writes to this */
3960static struct ieee80211_rate wl1271_rates[] = {
3961 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003962 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3963 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003964 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003965 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3966 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003967 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3968 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003969 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3970 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3972 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003973 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3974 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003975 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3976 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003977 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3978 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003979 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003980 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3981 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003982 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003983 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3984 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003985 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003986 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3987 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003988 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003989 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3990 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003991 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003992 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3993 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003994 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003995 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3996 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003997 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003998 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3999 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004000};
4001
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004002/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004003static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004004 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004005 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004006 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4007 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4008 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004009 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004010 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4011 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4012 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004013 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004014 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4015 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4016 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004017 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004018};
4019
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004020/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004021static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004022 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004023 7, /* CONF_HW_RXTX_RATE_MCS7 */
4024 6, /* CONF_HW_RXTX_RATE_MCS6 */
4025 5, /* CONF_HW_RXTX_RATE_MCS5 */
4026 4, /* CONF_HW_RXTX_RATE_MCS4 */
4027 3, /* CONF_HW_RXTX_RATE_MCS3 */
4028 2, /* CONF_HW_RXTX_RATE_MCS2 */
4029 1, /* CONF_HW_RXTX_RATE_MCS1 */
4030 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004031
4032 11, /* CONF_HW_RXTX_RATE_54 */
4033 10, /* CONF_HW_RXTX_RATE_48 */
4034 9, /* CONF_HW_RXTX_RATE_36 */
4035 8, /* CONF_HW_RXTX_RATE_24 */
4036
4037 /* TI-specific rate */
4038 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4039
4040 7, /* CONF_HW_RXTX_RATE_18 */
4041 6, /* CONF_HW_RXTX_RATE_12 */
4042 3, /* CONF_HW_RXTX_RATE_11 */
4043 5, /* CONF_HW_RXTX_RATE_9 */
4044 4, /* CONF_HW_RXTX_RATE_6 */
4045 2, /* CONF_HW_RXTX_RATE_5_5 */
4046 1, /* CONF_HW_RXTX_RATE_2 */
4047 0 /* CONF_HW_RXTX_RATE_1 */
4048};
4049
Shahar Levie8b03a22010-10-13 16:09:39 +02004050/* 11n STA capabilities */
4051#define HW_RX_HIGHEST_RATE 72
4052
Shahar Levi00d20102010-11-08 11:20:10 +00004053#ifdef CONFIG_WL12XX_HT
4054#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004055 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4056 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004057 .ht_supported = true, \
4058 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4059 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4060 .mcs = { \
4061 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4062 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4063 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4064 }, \
4065}
Shahar Levi18357852010-10-13 16:09:41 +02004066#else
Shahar Levi00d20102010-11-08 11:20:10 +00004067#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004068 .ht_supported = false, \
4069}
4070#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004071
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004072/* can't be const, mac80211 writes to this */
4073static struct ieee80211_supported_band wl1271_band_2ghz = {
4074 .channels = wl1271_channels,
4075 .n_channels = ARRAY_SIZE(wl1271_channels),
4076 .bitrates = wl1271_rates,
4077 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004078 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004079};
4080
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004081/* 5 GHz data rates for WL1273 */
4082static struct ieee80211_rate wl1271_rates_5ghz[] = {
4083 { .bitrate = 60,
4084 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4085 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4086 { .bitrate = 90,
4087 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4088 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4089 { .bitrate = 120,
4090 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4091 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4092 { .bitrate = 180,
4093 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4094 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4095 { .bitrate = 240,
4096 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4097 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4098 { .bitrate = 360,
4099 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4100 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4101 { .bitrate = 480,
4102 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4103 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4104 { .bitrate = 540,
4105 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4106 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4107};
4108
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004109/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004110static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004111 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4112 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4113 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4114 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4115 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4116 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4117 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4118 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4119 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4120 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4121 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4122 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4123 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4124 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4125 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4126 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4127 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4128 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4129 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4130 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4131 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4132 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4133 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4134 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4135 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4136 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4137 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4138 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4139 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4140 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4141 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4142 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4143 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4144 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004145};
4146
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004147/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004148static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004149 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004150 7, /* CONF_HW_RXTX_RATE_MCS7 */
4151 6, /* CONF_HW_RXTX_RATE_MCS6 */
4152 5, /* CONF_HW_RXTX_RATE_MCS5 */
4153 4, /* CONF_HW_RXTX_RATE_MCS4 */
4154 3, /* CONF_HW_RXTX_RATE_MCS3 */
4155 2, /* CONF_HW_RXTX_RATE_MCS2 */
4156 1, /* CONF_HW_RXTX_RATE_MCS1 */
4157 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004158
4159 7, /* CONF_HW_RXTX_RATE_54 */
4160 6, /* CONF_HW_RXTX_RATE_48 */
4161 5, /* CONF_HW_RXTX_RATE_36 */
4162 4, /* CONF_HW_RXTX_RATE_24 */
4163
4164 /* TI-specific rate */
4165 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4166
4167 3, /* CONF_HW_RXTX_RATE_18 */
4168 2, /* CONF_HW_RXTX_RATE_12 */
4169 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4170 1, /* CONF_HW_RXTX_RATE_9 */
4171 0, /* CONF_HW_RXTX_RATE_6 */
4172 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4173 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4174 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4175};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004176
4177static struct ieee80211_supported_band wl1271_band_5ghz = {
4178 .channels = wl1271_channels_5ghz,
4179 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4180 .bitrates = wl1271_rates_5ghz,
4181 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004182 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004183};
4184
Tobias Klausera0ea9492010-05-20 10:38:11 +02004185static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004186 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4187 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4188};
4189
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004190static const struct ieee80211_ops wl1271_ops = {
4191 .start = wl1271_op_start,
4192 .stop = wl1271_op_stop,
4193 .add_interface = wl1271_op_add_interface,
4194 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004195#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004196 .suspend = wl1271_op_suspend,
4197 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004198#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004199 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004200 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004201 .configure_filter = wl1271_op_configure_filter,
4202 .tx = wl1271_op_tx,
4203 .set_key = wl1271_op_set_key,
4204 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004205 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004206 .sched_scan_start = wl1271_op_sched_scan_start,
4207 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004208 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004209 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004210 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004211 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004212 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004213 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004214 .sta_add = wl1271_op_sta_add,
4215 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004216 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004217 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004218 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004219};
4220
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004221
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004222u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004223{
4224 u8 idx;
4225
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004226 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004227
4228 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4229 wl1271_error("Illegal RX rate from HW: %d", rate);
4230 return 0;
4231 }
4232
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004233 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004234 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4235 wl1271_error("Unsupported RX rate from HW: %d", rate);
4236 return 0;
4237 }
4238
4239 return idx;
4240}
4241
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004242static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4243 struct device_attribute *attr,
4244 char *buf)
4245{
4246 struct wl1271 *wl = dev_get_drvdata(dev);
4247 ssize_t len;
4248
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004249 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004250
4251 mutex_lock(&wl->mutex);
4252 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4253 wl->sg_enabled);
4254 mutex_unlock(&wl->mutex);
4255
4256 return len;
4257
4258}
4259
4260static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4261 struct device_attribute *attr,
4262 const char *buf, size_t count)
4263{
4264 struct wl1271 *wl = dev_get_drvdata(dev);
4265 unsigned long res;
4266 int ret;
4267
Luciano Coelho6277ed62011-04-01 17:49:54 +03004268 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004269 if (ret < 0) {
4270 wl1271_warning("incorrect value written to bt_coex_mode");
4271 return count;
4272 }
4273
4274 mutex_lock(&wl->mutex);
4275
4276 res = !!res;
4277
4278 if (res == wl->sg_enabled)
4279 goto out;
4280
4281 wl->sg_enabled = res;
4282
4283 if (wl->state == WL1271_STATE_OFF)
4284 goto out;
4285
Ido Yariva6208652011-03-01 15:14:41 +02004286 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004287 if (ret < 0)
4288 goto out;
4289
4290 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4291 wl1271_ps_elp_sleep(wl);
4292
4293 out:
4294 mutex_unlock(&wl->mutex);
4295 return count;
4296}
4297
4298static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4299 wl1271_sysfs_show_bt_coex_state,
4300 wl1271_sysfs_store_bt_coex_state);
4301
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004302static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4303 struct device_attribute *attr,
4304 char *buf)
4305{
4306 struct wl1271 *wl = dev_get_drvdata(dev);
4307 ssize_t len;
4308
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004309 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004310
4311 mutex_lock(&wl->mutex);
4312 if (wl->hw_pg_ver >= 0)
4313 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4314 else
4315 len = snprintf(buf, len, "n/a\n");
4316 mutex_unlock(&wl->mutex);
4317
4318 return len;
4319}
4320
Gery Kahn6f07b722011-07-18 14:21:49 +03004321static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004322 wl1271_sysfs_show_hw_pg_ver, NULL);
4323
Ido Yariv95dac04f2011-06-06 14:57:06 +03004324static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4325 struct bin_attribute *bin_attr,
4326 char *buffer, loff_t pos, size_t count)
4327{
4328 struct device *dev = container_of(kobj, struct device, kobj);
4329 struct wl1271 *wl = dev_get_drvdata(dev);
4330 ssize_t len;
4331 int ret;
4332
4333 ret = mutex_lock_interruptible(&wl->mutex);
4334 if (ret < 0)
4335 return -ERESTARTSYS;
4336
4337 /* Let only one thread read the log at a time, blocking others */
4338 while (wl->fwlog_size == 0) {
4339 DEFINE_WAIT(wait);
4340
4341 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4342 &wait,
4343 TASK_INTERRUPTIBLE);
4344
4345 if (wl->fwlog_size != 0) {
4346 finish_wait(&wl->fwlog_waitq, &wait);
4347 break;
4348 }
4349
4350 mutex_unlock(&wl->mutex);
4351
4352 schedule();
4353 finish_wait(&wl->fwlog_waitq, &wait);
4354
4355 if (signal_pending(current))
4356 return -ERESTARTSYS;
4357
4358 ret = mutex_lock_interruptible(&wl->mutex);
4359 if (ret < 0)
4360 return -ERESTARTSYS;
4361 }
4362
4363 /* Check if the fwlog is still valid */
4364 if (wl->fwlog_size < 0) {
4365 mutex_unlock(&wl->mutex);
4366 return 0;
4367 }
4368
4369 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4370 len = min(count, (size_t)wl->fwlog_size);
4371 wl->fwlog_size -= len;
4372 memcpy(buffer, wl->fwlog, len);
4373
4374 /* Make room for new messages */
4375 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4376
4377 mutex_unlock(&wl->mutex);
4378
4379 return len;
4380}
4381
4382static struct bin_attribute fwlog_attr = {
4383 .attr = {.name = "fwlog", .mode = S_IRUSR},
4384 .read = wl1271_sysfs_read_fwlog,
4385};
4386
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004387int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004388{
4389 int ret;
4390
4391 if (wl->mac80211_registered)
4392 return 0;
4393
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004394 ret = wl1271_fetch_nvs(wl);
4395 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004396 /* NOTE: The wl->nvs->nvs element must be first, in
4397 * order to simplify the casting, we assume it is at
4398 * the beginning of the wl->nvs structure.
4399 */
4400 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004401
4402 wl->mac_addr[0] = nvs_ptr[11];
4403 wl->mac_addr[1] = nvs_ptr[10];
4404 wl->mac_addr[2] = nvs_ptr[6];
4405 wl->mac_addr[3] = nvs_ptr[5];
4406 wl->mac_addr[4] = nvs_ptr[4];
4407 wl->mac_addr[5] = nvs_ptr[3];
4408 }
4409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4411
4412 ret = ieee80211_register_hw(wl->hw);
4413 if (ret < 0) {
4414 wl1271_error("unable to register mac80211 hw: %d", ret);
4415 return ret;
4416 }
4417
4418 wl->mac80211_registered = true;
4419
Eliad Pellerd60080a2010-11-24 12:53:16 +02004420 wl1271_debugfs_init(wl);
4421
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004422 register_netdevice_notifier(&wl1271_dev_notifier);
4423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004424 wl1271_notice("loaded");
4425
4426 return 0;
4427}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004428EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004430void wl1271_unregister_hw(struct wl1271 *wl)
4431{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004432 if (wl->state == WL1271_STATE_PLT)
4433 __wl1271_plt_stop(wl);
4434
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004435 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004436 ieee80211_unregister_hw(wl->hw);
4437 wl->mac80211_registered = false;
4438
4439}
4440EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4441
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004442int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004444 static const u32 cipher_suites[] = {
4445 WLAN_CIPHER_SUITE_WEP40,
4446 WLAN_CIPHER_SUITE_WEP104,
4447 WLAN_CIPHER_SUITE_TKIP,
4448 WLAN_CIPHER_SUITE_CCMP,
4449 WL1271_CIPHER_SUITE_GEM,
4450 };
4451
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004452 /* The tx descriptor buffer and the TKIP space. */
4453 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4454 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455
4456 /* unit us */
4457 /* FIXME: find a proper value */
4458 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004459 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004460
4461 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004462 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004463 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004464 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004465 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004466 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004467 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004468 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004469 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004470 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004472 wl->hw->wiphy->cipher_suites = cipher_suites;
4473 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4474
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004475 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004476 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004477 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004478 /*
4479 * Maximum length of elements in scanning probe request templates
4480 * should be the maximum length possible for a template, without
4481 * the IEEE80211 header of the template
4482 */
Eliad Peller154037d2011-08-14 13:17:12 +03004483 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004484 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004485
Luciano Coelho4a31c112011-03-21 23:16:14 +02004486 /* make sure all our channels fit in the scanned_ch bitmask */
4487 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4488 ARRAY_SIZE(wl1271_channels_5ghz) >
4489 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004490 /*
4491 * We keep local copies of the band structs because we need to
4492 * modify them on a per-device basis.
4493 */
4494 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4495 sizeof(wl1271_band_2ghz));
4496 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4497 sizeof(wl1271_band_5ghz));
4498
4499 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4500 &wl->bands[IEEE80211_BAND_2GHZ];
4501 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4502 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004503
Kalle Valo12bd8942010-03-18 12:26:33 +02004504 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004505 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004506
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004507 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4508
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004509 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004510
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004511 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4512
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004513 wl->hw->max_rx_aggregation_subframes = 8;
4514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004515 return 0;
4516}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004517EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004519#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004520
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004521struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004522{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004523 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004524 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004525 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004526 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004527 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528
4529 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4530 if (!hw) {
4531 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004532 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004533 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004534 }
4535
Julia Lawall929ebd32010-05-15 23:16:39 +02004536 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004537 if (!plat_dev) {
4538 wl1271_error("could not allocate platform_device");
4539 ret = -ENOMEM;
4540 goto err_plat_alloc;
4541 }
4542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004543 wl = hw->priv;
4544 memset(wl, 0, sizeof(*wl));
4545
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004546 INIT_LIST_HEAD(&wl->list);
4547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004548 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004549 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004550
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004551 for (i = 0; i < NUM_TX_QUEUES; i++)
4552 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004553
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004554 for (i = 0; i < NUM_TX_QUEUES; i++)
4555 for (j = 0; j < AP_MAX_LINKS; j++)
4556 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4557
Ido Yariva6208652011-03-01 15:14:41 +02004558 skb_queue_head_init(&wl->deferred_rx_queue);
4559 skb_queue_head_init(&wl->deferred_tx_queue);
4560
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004561 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004562 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004563 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004564 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4565 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4566 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004567 INIT_WORK(&wl->rx_streaming_enable_work,
4568 wl1271_rx_streaming_enable_work);
4569 INIT_WORK(&wl->rx_streaming_disable_work,
4570 wl1271_rx_streaming_disable_work);
4571
Eliad Peller92ef8962011-06-07 12:50:46 +03004572 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4573 if (!wl->freezable_wq) {
4574 ret = -ENOMEM;
4575 goto err_hw;
4576 }
4577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004578 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004579 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004580 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004581 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004582 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004583 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004584 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004585 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004586 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004587 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004588 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004589 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004590 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004591 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004592 wl->bss_type = MAX_BSS_TYPE;
4593 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004594 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004595 wl->ap_ps_map = 0;
4596 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004597 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004598 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004599 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004600 wl->tx_security_seq = 0;
4601 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004602 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004603 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004604 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004605 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4606 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004607 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004608 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4609 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004610 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4611 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004612 wl->fwlog_size = 0;
4613 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004614
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004615 /* The system link is always allocated */
4616 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4617
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004618 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004619 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004620 wl->tx_frames[i] = NULL;
4621
4622 spin_lock_init(&wl->wl_lock);
4623
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004624 wl->state = WL1271_STATE_OFF;
4625 mutex_init(&wl->mutex);
4626
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004627 /* Apply default driver configuration. */
4628 wl1271_conf_init(wl);
4629
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004630 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4631 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4632 if (!wl->aggr_buf) {
4633 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004634 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004635 }
4636
Ido Yariv990f5de2011-03-31 10:06:59 +02004637 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4638 if (!wl->dummy_packet) {
4639 ret = -ENOMEM;
4640 goto err_aggr;
4641 }
4642
Ido Yariv95dac04f2011-06-06 14:57:06 +03004643 /* Allocate one page for the FW log */
4644 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4645 if (!wl->fwlog) {
4646 ret = -ENOMEM;
4647 goto err_dummy_packet;
4648 }
4649
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004650 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004651 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004652 if (ret) {
4653 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004654 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004655 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004656 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004657
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004658 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004659 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004660 if (ret < 0) {
4661 wl1271_error("failed to create sysfs file bt_coex_state");
4662 goto err_platform;
4663 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004664
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004665 /* Create sysfs file to get HW PG version */
4666 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4667 if (ret < 0) {
4668 wl1271_error("failed to create sysfs file hw_pg_ver");
4669 goto err_bt_coex_state;
4670 }
4671
Ido Yariv95dac04f2011-06-06 14:57:06 +03004672 /* Create sysfs file for the FW log */
4673 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4674 if (ret < 0) {
4675 wl1271_error("failed to create sysfs file fwlog");
4676 goto err_hw_pg_ver;
4677 }
4678
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004679 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004680
Ido Yariv95dac04f2011-06-06 14:57:06 +03004681err_hw_pg_ver:
4682 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4683
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004684err_bt_coex_state:
4685 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4686
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004687err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004688 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004689
Ido Yariv95dac04f2011-06-06 14:57:06 +03004690err_fwlog:
4691 free_page((unsigned long)wl->fwlog);
4692
Ido Yariv990f5de2011-03-31 10:06:59 +02004693err_dummy_packet:
4694 dev_kfree_skb(wl->dummy_packet);
4695
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004696err_aggr:
4697 free_pages((unsigned long)wl->aggr_buf, order);
4698
Eliad Peller92ef8962011-06-07 12:50:46 +03004699err_wq:
4700 destroy_workqueue(wl->freezable_wq);
4701
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004702err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004703 wl1271_debugfs_exit(wl);
4704 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004705
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004706err_plat_alloc:
4707 ieee80211_free_hw(hw);
4708
4709err_hw_alloc:
4710
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004711 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004712}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004713EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004714
4715int wl1271_free_hw(struct wl1271 *wl)
4716{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004717 /* Unblock any fwlog readers */
4718 mutex_lock(&wl->mutex);
4719 wl->fwlog_size = -1;
4720 wake_up_interruptible_all(&wl->fwlog_waitq);
4721 mutex_unlock(&wl->mutex);
4722
4723 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004724
4725 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4726
4727 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004728 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004729 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004730 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004731 free_pages((unsigned long)wl->aggr_buf,
4732 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004733 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004734
4735 wl1271_debugfs_exit(wl);
4736
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004737 vfree(wl->fw);
4738 wl->fw = NULL;
4739 kfree(wl->nvs);
4740 wl->nvs = NULL;
4741
4742 kfree(wl->fw_status);
4743 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004744 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004745
4746 ieee80211_free_hw(wl->hw);
4747
4748 return 0;
4749}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004750EXPORT_SYMBOL_GPL(wl1271_free_hw);
4751
Guy Eilam491bbd62011-01-12 10:33:29 +01004752u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004753EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004754module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004755MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4756
Ido Yariv95dac04f2011-06-06 14:57:06 +03004757module_param_named(fwlog, fwlog_param, charp, 0);
4758MODULE_PARM_DESC(keymap,
4759 "FW logger options: continuous, ondemand, dbgpins or disable");
4760
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004761MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004762MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004763MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");