blob: ad0b5a163b9d62496d071ccf19b0db88cb674061 [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{
782 int id = hlid - WL1271_AP_STA_HLID_START;
783 return test_bit(id, wl->ap_hlid_map);
784}
785
786static void wl12xx_irq_update_links_status(struct wl1271 *wl,
787 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200788{
789 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300790 u8 hlid, cnt;
791
792 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200793
794 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
795 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
796 wl1271_debug(DEBUG_PSM,
797 "link ps prev 0x%x cur 0x%x changed 0x%x",
798 wl->ap_fw_ps_map, cur_fw_ps_map,
799 wl->ap_fw_ps_map ^ cur_fw_ps_map);
800
801 wl->ap_fw_ps_map = cur_fw_ps_map;
802 }
803
804 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300805 if (!wl1271_is_active_sta(wl, hlid))
806 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200807
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300808 cnt = status->tx_lnk_free_pkts[hlid] -
809 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200810
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300811 wl->links[hlid].prev_freed_pkts =
812 status->tx_lnk_free_pkts[hlid];
813 wl->links[hlid].allocated_pkts -= cnt;
814
815 wl12xx_irq_ps_regulate_link(wl, hlid,
816 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817 }
818}
819
Eliad Peller4d56ad92011-08-14 13:17:05 +0300820static void wl12xx_fw_status(struct wl1271 *wl,
821 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200823 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200824 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300825 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300826 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827
Eliad Peller4d56ad92011-08-14 13:17:05 +0300828 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200829
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
831 "drv_rx_counter = %d, tx_results_counter = %d)",
832 status->intr,
833 status->fw_rx_counter,
834 status->drv_rx_counter,
835 status->tx_results_counter);
836
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300837 for (i = 0; i < NUM_TX_QUEUES; i++) {
838 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300839 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300840 (status->tx_released_pkts[i] -
841 wl->tx_pkts_freed[i]) & 0xff;
842
843 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
844 }
845
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300846 /* prevent wrap-around in total blocks counter */
847 if (likely(wl->tx_blocks_freed <=
848 le32_to_cpu(status->total_released_blks)))
849 freed_blocks = le32_to_cpu(status->total_released_blks) -
850 wl->tx_blocks_freed;
851 else
852 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
853 le32_to_cpu(status->total_released_blks);
854
Eliad Peller4d56ad92011-08-14 13:17:05 +0300855 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200856
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300857 wl->tx_allocated_blocks -= freed_blocks;
858
Eliad Peller4d56ad92011-08-14 13:17:05 +0300859 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200860
Eliad Peller4d56ad92011-08-14 13:17:05 +0300861 /*
862 * The FW might change the total number of TX memblocks before
863 * we get a notification about blocks being released. Thus, the
864 * available blocks calculation might yield a temporary result
865 * which is lower than the actual available blocks. Keeping in
866 * mind that only blocks that were allocated can be moved from
867 * TX to RX, tx_blocks_available should never decrease here.
868 */
869 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
870 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871
Ido Yariva5225502010-10-12 14:49:10 +0200872 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200873 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200874 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300875
Eliad Peller4d56ad92011-08-14 13:17:05 +0300876 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300877 if (wl->bss_type == BSS_TYPE_AP_BSS)
878 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200881 getnstimeofday(&ts);
882 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
883 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884}
885
Ido Yariva6208652011-03-01 15:14:41 +0200886static void wl1271_flush_deferred_work(struct wl1271 *wl)
887{
888 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200889
Ido Yariva6208652011-03-01 15:14:41 +0200890 /* Pass all received frames to the network stack */
891 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
892 ieee80211_rx_ni(wl->hw, skb);
893
894 /* Return sent skbs to the network stack */
895 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300896 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200897}
898
899static void wl1271_netstack_work(struct work_struct *work)
900{
901 struct wl1271 *wl =
902 container_of(work, struct wl1271, netstack_work);
903
904 do {
905 wl1271_flush_deferred_work(wl);
906 } while (skb_queue_len(&wl->deferred_rx_queue));
907}
908
909#define WL1271_IRQ_MAX_LOOPS 256
910
911irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300914 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200915 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200916 struct wl1271 *wl = (struct wl1271 *)cookie;
917 bool done = false;
918 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200919 unsigned long flags;
920
921 /* TX might be handled here, avoid redundant work */
922 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
923 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924
Ido Yariv341b7cd2011-03-31 10:07:01 +0200925 /*
926 * In case edge triggered interrupt must be used, we cannot iterate
927 * more than once without introducing race conditions with the hardirq.
928 */
929 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
930 loopcount = 1;
931
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 mutex_lock(&wl->mutex);
933
934 wl1271_debug(DEBUG_IRQ, "IRQ work");
935
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200936 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 goto out;
938
Ido Yariva6208652011-03-01 15:14:41 +0200939 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 if (ret < 0)
941 goto out;
942
Ido Yariva6208652011-03-01 15:14:41 +0200943 while (!done && loopcount--) {
944 /*
945 * In order to avoid a race with the hardirq, clear the flag
946 * before acknowledging the chip. Since the mutex is held,
947 * wl1271_ps_elp_wakeup cannot be called concurrently.
948 */
949 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
950 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200951
Eliad Peller4d56ad92011-08-14 13:17:05 +0300952 wl12xx_fw_status(wl, wl->fw_status);
953 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200954 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200955 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200956 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200957 continue;
958 }
959
Eliad Pellerccc83b02010-10-27 14:09:57 +0200960 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
961 wl1271_error("watchdog interrupt received! "
962 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300963 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200964
965 /* restarting the chip. ignore any other interrupt. */
966 goto out;
967 }
968
Ido Yariva6208652011-03-01 15:14:41 +0200969 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200970 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
971
Eliad Peller4d56ad92011-08-14 13:17:05 +0300972 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200973
Ido Yariva5225502010-10-12 14:49:10 +0200974 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200976 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300977 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200978 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200979 /*
980 * In order to avoid starvation of the TX path,
981 * call the work function directly.
982 */
983 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200984 } else {
985 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200986 }
987
Ido Yariv8aad2462011-03-01 15:14:38 +0200988 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300989 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200990 (wl->tx_results_count & 0xff))
991 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200992
993 /* Make sure the deferred queues don't get too long */
994 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
995 skb_queue_len(&wl->deferred_rx_queue);
996 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
997 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200998 }
999
1000 if (intr & WL1271_ACX_INTR_EVENT_A) {
1001 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1002 wl1271_event_handle(wl, 0);
1003 }
1004
1005 if (intr & WL1271_ACX_INTR_EVENT_B) {
1006 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1007 wl1271_event_handle(wl, 1);
1008 }
1009
1010 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1011 wl1271_debug(DEBUG_IRQ,
1012 "WL1271_ACX_INTR_INIT_COMPLETE");
1013
1014 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1015 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 }
1017
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 wl1271_ps_elp_sleep(wl);
1019
1020out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001021 spin_lock_irqsave(&wl->wl_lock, flags);
1022 /* In case TX was not handled here, queue TX work */
1023 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1024 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001025 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001026 ieee80211_queue_work(wl->hw, &wl->tx_work);
1027 spin_unlock_irqrestore(&wl->wl_lock, flags);
1028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001030
1031 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032}
Ido Yariva6208652011-03-01 15:14:41 +02001033EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035static int wl1271_fetch_firmware(struct wl1271 *wl)
1036{
1037 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001038 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 int ret;
1040
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001041 if (wl->chip.id == CHIP_ID_1283_PG20)
1042 fw_name = WL128X_FW_NAME;
1043 else
1044 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045
1046 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1047
1048 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049
1050 if (ret < 0) {
1051 wl1271_error("could not get firmware: %d", ret);
1052 return ret;
1053 }
1054
1055 if (fw->size % 4) {
1056 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1057 fw->size);
1058 ret = -EILSEQ;
1059 goto out;
1060 }
1061
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001064 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065
1066 if (!wl->fw) {
1067 wl1271_error("could not allocate memory for the firmware");
1068 ret = -ENOMEM;
1069 goto out;
1070 }
1071
1072 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073 ret = 0;
1074
1075out:
1076 release_firmware(fw);
1077
1078 return ret;
1079}
1080
1081static int wl1271_fetch_nvs(struct wl1271 *wl)
1082{
1083 const struct firmware *fw;
1084 int ret;
1085
Shahar Levi5aa42342011-03-06 16:32:07 +02001086 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
1088 if (ret < 0) {
1089 wl1271_error("could not get nvs file: %d", ret);
1090 return ret;
1091 }
1092
Shahar Levibc765bf2011-03-06 16:32:10 +02001093 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 if (!wl->nvs) {
1096 wl1271_error("could not allocate memory for the nvs file");
1097 ret = -ENOMEM;
1098 goto out;
1099 }
1100
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001101 wl->nvs_len = fw->size;
1102
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103out:
1104 release_firmware(fw);
1105
1106 return ret;
1107}
1108
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001109void wl12xx_queue_recovery_work(struct wl1271 *wl)
1110{
1111 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1112 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1113}
1114
Ido Yariv95dac04f2011-06-06 14:57:06 +03001115size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1116{
1117 size_t len = 0;
1118
1119 /* The FW log is a length-value list, find where the log end */
1120 while (len < maxlen) {
1121 if (memblock[len] == 0)
1122 break;
1123 if (len + memblock[len] + 1 > maxlen)
1124 break;
1125 len += memblock[len] + 1;
1126 }
1127
1128 /* Make sure we have enough room */
1129 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1130
1131 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1132 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1133 wl->fwlog_size += len;
1134
1135 return len;
1136}
1137
1138static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1139{
1140 u32 addr;
1141 u32 first_addr;
1142 u8 *block;
1143
1144 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1145 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1146 (wl->conf.fwlog.mem_blocks == 0))
1147 return;
1148
1149 wl1271_info("Reading FW panic log");
1150
1151 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1152 if (!block)
1153 return;
1154
1155 /*
1156 * Make sure the chip is awake and the logger isn't active.
1157 * This might fail if the firmware hanged.
1158 */
1159 if (!wl1271_ps_elp_wakeup(wl))
1160 wl12xx_cmd_stop_fwlog(wl);
1161
1162 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001163 wl12xx_fw_status(wl, wl->fw_status);
1164 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001165 if (!first_addr)
1166 goto out;
1167
1168 /* Traverse the memory blocks linked list */
1169 addr = first_addr;
1170 do {
1171 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1172 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1173 false);
1174
1175 /*
1176 * Memory blocks are linked to one another. The first 4 bytes
1177 * of each memory block hold the hardware address of the next
1178 * one. The last memory block points to the first one.
1179 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001180 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001181 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1182 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1183 break;
1184 } while (addr && (addr != first_addr));
1185
1186 wake_up_interruptible(&wl->fwlog_waitq);
1187
1188out:
1189 kfree(block);
1190}
1191
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001192static void wl1271_recovery_work(struct work_struct *work)
1193{
1194 struct wl1271 *wl =
1195 container_of(work, struct wl1271, recovery_work);
1196
1197 mutex_lock(&wl->mutex);
1198
1199 if (wl->state != WL1271_STATE_ON)
1200 goto out;
1201
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001202 /* Avoid a recursive recovery */
1203 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1204
Ido Yariv95dac04f2011-06-06 14:57:06 +03001205 wl12xx_read_fwlog_panic(wl);
1206
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001207 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1208 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209
Oz Krakowskib992c682011-06-26 10:36:02 +03001210 /*
1211 * Advance security sequence number to overcome potential progress
1212 * in the firmware during recovery. This doens't hurt if the network is
1213 * not encrypted.
1214 */
1215 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1216 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1217 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1218
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001219 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1220 ieee80211_connection_loss(wl->vif);
1221
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001222 /* Prevent spurious TX during FW restart */
1223 ieee80211_stop_queues(wl->hw);
1224
Luciano Coelho33c2c062011-05-10 14:46:02 +03001225 if (wl->sched_scanning) {
1226 ieee80211_sched_scan_stopped(wl->hw);
1227 wl->sched_scanning = false;
1228 }
1229
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001230 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001231 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001232
1233 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1234
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001235 ieee80211_restart_hw(wl->hw);
1236
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001237 /*
1238 * Its safe to enable TX now - the queues are stopped after a request
1239 * to restart the HW.
1240 */
1241 ieee80211_wake_queues(wl->hw);
1242
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001243out:
1244 mutex_unlock(&wl->mutex);
1245}
1246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247static void wl1271_fw_wakeup(struct wl1271 *wl)
1248{
1249 u32 elp_reg;
1250
1251 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001252 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253}
1254
1255static int wl1271_setup(struct wl1271 *wl)
1256{
1257 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1258 if (!wl->fw_status)
1259 return -ENOMEM;
1260
1261 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1262 if (!wl->tx_res_if) {
1263 kfree(wl->fw_status);
1264 return -ENOMEM;
1265 }
1266
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267 return 0;
1268}
1269
1270static int wl1271_chip_wakeup(struct wl1271 *wl)
1271{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001272 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 int ret = 0;
1274
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001275 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001276 ret = wl1271_power_on(wl);
1277 if (ret < 0)
1278 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001280 wl1271_io_reset(wl);
1281 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282
1283 /* We don't need a real memory partition here, because we only want
1284 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001285 memset(&partition, 0, sizeof(partition));
1286 partition.reg.start = REGISTERS_BASE;
1287 partition.reg.size = REGISTERS_DOWN_SIZE;
1288 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289
1290 /* ELP module wake up */
1291 wl1271_fw_wakeup(wl);
1292
1293 /* whal_FwCtrl_BootSm() */
1294
1295 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001296 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297
1298 /* 1. check if chip id is valid */
1299
1300 switch (wl->chip.id) {
1301 case CHIP_ID_1271_PG10:
1302 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1303 wl->chip.id);
1304
1305 ret = wl1271_setup(wl);
1306 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 break;
1309 case CHIP_ID_1271_PG20:
1310 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1311 wl->chip.id);
1312
Shahar Levi0c005042011-06-12 10:34:43 +03001313 /*
1314 * 'end-of-transaction flag' and 'LPD mode flag'
1315 * should be set in wl127x AP mode only
1316 */
Shahar Levi564f5952011-04-04 10:20:39 +03001317 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001318 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1319 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001320
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 ret = wl1271_setup(wl);
1322 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001323 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001325 case CHIP_ID_1283_PG20:
1326 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1327 wl->chip.id);
1328
1329 ret = wl1271_setup(wl);
1330 if (ret < 0)
1331 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001332
Ido Yariv0da13da2011-03-31 10:06:58 +02001333 if (wl1271_set_block_size(wl))
1334 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001335 break;
1336 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001338 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001340 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 }
1342
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001343 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344 ret = wl1271_fetch_firmware(wl);
1345 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001346 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 }
1348
1349 /* No NVS from netlink, try to get it from the filesystem */
1350 if (wl->nvs == NULL) {
1351 ret = wl1271_fetch_nvs(wl);
1352 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 }
1355
1356out:
1357 return ret;
1358}
1359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360int wl1271_plt_start(struct wl1271 *wl)
1361{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001362 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001363 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 int ret;
1365
1366 mutex_lock(&wl->mutex);
1367
1368 wl1271_notice("power up");
1369
1370 if (wl->state != WL1271_STATE_OFF) {
1371 wl1271_error("cannot go into PLT state because not "
1372 "in off state: %d", wl->state);
1373 ret = -EBUSY;
1374 goto out;
1375 }
1376
Arik Nemtsov166d5042010-10-16 21:44:57 +02001377 wl->bss_type = BSS_TYPE_STA_BSS;
1378
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001379 while (retries) {
1380 retries--;
1381 ret = wl1271_chip_wakeup(wl);
1382 if (ret < 0)
1383 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 ret = wl1271_boot(wl);
1386 if (ret < 0)
1387 goto power_off;
1388
1389 ret = wl1271_plt_init(wl);
1390 if (ret < 0)
1391 goto irq_disable;
1392
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001393 wl->state = WL1271_STATE_PLT;
1394 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001395 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001396
Gery Kahn6f07b722011-07-18 14:21:49 +03001397 /* update hw/fw version info in wiphy struct */
1398 wiphy->hw_version = wl->chip.id;
1399 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1400 sizeof(wiphy->fw_version));
1401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 goto out;
1403
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001404irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001405 mutex_unlock(&wl->mutex);
1406 /* Unlocking the mutex in the middle of handling is
1407 inherently unsafe. In this case we deem it safe to do,
1408 because we need to let any possibly pending IRQ out of
1409 the system (and while we are WL1271_STATE_OFF the IRQ
1410 work function will not do anything.) Also, any other
1411 possible concurrent operations will fail due to the
1412 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001413 wl1271_disable_interrupts(wl);
1414 wl1271_flush_deferred_work(wl);
1415 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001416 mutex_lock(&wl->mutex);
1417power_off:
1418 wl1271_power_off(wl);
1419 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001421 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1422 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423out:
1424 mutex_unlock(&wl->mutex);
1425
1426 return ret;
1427}
1428
Luciano Coelho4623ec72011-03-21 19:26:41 +02001429static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430{
1431 int ret = 0;
1432
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433 wl1271_notice("power down");
1434
1435 if (wl->state != WL1271_STATE_PLT) {
1436 wl1271_error("cannot power down because not in PLT "
1437 "state: %d", wl->state);
1438 ret = -EBUSY;
1439 goto out;
1440 }
1441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442 wl1271_power_off(wl);
1443
1444 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001445 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001448 wl1271_disable_interrupts(wl);
1449 wl1271_flush_deferred_work(wl);
1450 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001451 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001452 mutex_lock(&wl->mutex);
1453out:
1454 return ret;
1455}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001456
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001457int wl1271_plt_stop(struct wl1271 *wl)
1458{
1459 int ret;
1460
1461 mutex_lock(&wl->mutex);
1462 ret = __wl1271_plt_stop(wl);
1463 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 return ret;
1465}
1466
Johannes Berg7bb45682011-02-24 14:42:06 +01001467static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468{
1469 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001470 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001471 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001472 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001474 mapping = skb_get_queue_mapping(skb);
1475 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001476
1477 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001478 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001479
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001480 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001481
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001482 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001483
1484 /*
1485 * The workqueue is slow to process the tx_queue and we need stop
1486 * the queue here, otherwise the queue will get too long.
1487 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001488 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1490 ieee80211_stop_queue(wl->hw, mapping);
1491 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001492 }
1493
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001494 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001495 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001496 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1497 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1498 } else {
1499 skb_queue_tail(&wl->tx_queue[q], skb);
1500 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501
1502 /*
1503 * The chip specific setup must run before the first TX packet -
1504 * before that, the tx_work will not be initialized!
1505 */
1506
Ido Yarivb07d4032011-03-01 15:14:43 +02001507 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1508 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001509 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001510
1511 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512}
1513
Shahar Leviae47c452011-03-06 16:32:14 +02001514int wl1271_tx_dummy_packet(struct wl1271 *wl)
1515{
Ido Yariv990f5de2011-03-31 10:06:59 +02001516 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001517 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001518
Ido Yariv990f5de2011-03-31 10:06:59 +02001519 spin_lock_irqsave(&wl->wl_lock, flags);
1520 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001521 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001522 spin_unlock_irqrestore(&wl->wl_lock, flags);
1523
1524 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1525 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1526 wl1271_tx_work_locked(wl);
1527
1528 /*
1529 * If the FW TX is busy, TX work will be scheduled by the threaded
1530 * interrupt handler function
1531 */
1532 return 0;
1533}
1534
1535/*
1536 * The size of the dummy packet should be at least 1400 bytes. However, in
1537 * order to minimize the number of bus transactions, aligning it to 512 bytes
1538 * boundaries could be beneficial, performance wise
1539 */
1540#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1541
Luciano Coelhocf27d862011-04-01 21:08:23 +03001542static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001543{
1544 struct sk_buff *skb;
1545 struct ieee80211_hdr_3addr *hdr;
1546 unsigned int dummy_packet_size;
1547
1548 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1549 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1550
1551 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001552 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001553 wl1271_warning("Failed to allocate a dummy packet skb");
1554 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001555 }
1556
1557 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1558
1559 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1560 memset(hdr, 0, sizeof(*hdr));
1561 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 IEEE80211_STYPE_NULLFUNC |
1563 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001564
Ido Yariv990f5de2011-03-31 10:06:59 +02001565 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001566
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001567 /* Dummy packets require the TID to be management */
1568 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001569
1570 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001571 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001572 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001573
Ido Yariv990f5de2011-03-31 10:06:59 +02001574 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001575}
1576
Ido Yariv990f5de2011-03-31 10:06:59 +02001577
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001578static struct notifier_block wl1271_dev_notifier = {
1579 .notifier_call = wl1271_dev_notify,
1580};
1581
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001582#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001583static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001584{
Eliad Pellere85d1622011-06-27 13:06:43 +03001585 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001586
Eliad Peller94390642011-05-13 11:57:13 +03001587 mutex_lock(&wl->mutex);
1588
Eliad Pellere85d1622011-06-27 13:06:43 +03001589 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1590 goto out_unlock;
1591
Eliad Peller94390642011-05-13 11:57:13 +03001592 ret = wl1271_ps_elp_wakeup(wl);
1593 if (ret < 0)
1594 goto out_unlock;
1595
1596 /* enter psm if needed*/
1597 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1598 DECLARE_COMPLETION_ONSTACK(compl);
1599
1600 wl->ps_compl = &compl;
1601 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1602 wl->basic_rate, true);
1603 if (ret < 0)
1604 goto out_sleep;
1605
1606 /* we must unlock here so we will be able to get events */
1607 wl1271_ps_elp_sleep(wl);
1608 mutex_unlock(&wl->mutex);
1609
1610 ret = wait_for_completion_timeout(
1611 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1612 if (ret <= 0) {
1613 wl1271_warning("couldn't enter ps mode!");
1614 ret = -EBUSY;
1615 goto out;
1616 }
1617
1618 /* take mutex again, and wakeup */
1619 mutex_lock(&wl->mutex);
1620
1621 ret = wl1271_ps_elp_wakeup(wl);
1622 if (ret < 0)
1623 goto out_unlock;
1624 }
1625out_sleep:
1626 wl1271_ps_elp_sleep(wl);
1627out_unlock:
1628 mutex_unlock(&wl->mutex);
1629out:
1630 return ret;
1631
1632}
1633
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001634static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001635{
Eliad Pellere85d1622011-06-27 13:06:43 +03001636 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001637
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001638 mutex_lock(&wl->mutex);
1639
Eliad Pellere85d1622011-06-27 13:06:43 +03001640 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1641 goto out_unlock;
1642
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001643 ret = wl1271_ps_elp_wakeup(wl);
1644 if (ret < 0)
1645 goto out_unlock;
1646
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001647 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001648
1649 wl1271_ps_elp_sleep(wl);
1650out_unlock:
1651 mutex_unlock(&wl->mutex);
1652 return ret;
1653
1654}
1655
1656static int wl1271_configure_suspend(struct wl1271 *wl)
1657{
1658 if (wl->bss_type == BSS_TYPE_STA_BSS)
1659 return wl1271_configure_suspend_sta(wl);
1660 if (wl->bss_type == BSS_TYPE_AP_BSS)
1661 return wl1271_configure_suspend_ap(wl);
1662 return 0;
1663}
1664
1665static void wl1271_configure_resume(struct wl1271 *wl)
1666{
1667 int ret;
1668 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1669 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1670
1671 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001672 return;
1673
1674 mutex_lock(&wl->mutex);
1675 ret = wl1271_ps_elp_wakeup(wl);
1676 if (ret < 0)
1677 goto out;
1678
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001679 if (is_sta) {
1680 /* exit psm if it wasn't configured */
1681 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1682 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1683 wl->basic_rate, true);
1684 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001685 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001686 }
Eliad Peller94390642011-05-13 11:57:13 +03001687
1688 wl1271_ps_elp_sleep(wl);
1689out:
1690 mutex_unlock(&wl->mutex);
1691}
1692
Eliad Peller402e48612011-05-13 11:57:09 +03001693static int wl1271_op_suspend(struct ieee80211_hw *hw,
1694 struct cfg80211_wowlan *wow)
1695{
1696 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001697 int ret;
1698
Eliad Peller402e48612011-05-13 11:57:09 +03001699 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001700 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001701
Eliad Peller4a859df2011-06-06 12:21:52 +03001702 wl->wow_enabled = true;
1703 ret = wl1271_configure_suspend(wl);
1704 if (ret < 0) {
1705 wl1271_warning("couldn't prepare device to suspend");
1706 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001707 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001708 /* flush any remaining work */
1709 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001710
1711 /*
1712 * disable and re-enable interrupts in order to flush
1713 * the threaded_irq
1714 */
1715 wl1271_disable_interrupts(wl);
1716
1717 /*
1718 * set suspended flag to avoid triggering a new threaded_irq
1719 * work. no need for spinlock as interrupts are disabled.
1720 */
1721 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1722
1723 wl1271_enable_interrupts(wl);
1724 flush_work(&wl->tx_work);
1725 flush_delayed_work(&wl->pspoll_work);
1726 flush_delayed_work(&wl->elp_work);
1727
Eliad Peller402e48612011-05-13 11:57:09 +03001728 return 0;
1729}
1730
1731static int wl1271_op_resume(struct ieee80211_hw *hw)
1732{
1733 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 unsigned long flags;
1735 bool run_irq_work = false;
1736
Eliad Peller402e48612011-05-13 11:57:09 +03001737 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1738 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
1741 /*
1742 * re-enable irq_work enqueuing, and call irq_work directly if
1743 * there is a pending work.
1744 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 spin_lock_irqsave(&wl->wl_lock, flags);
1746 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1747 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1748 run_irq_work = true;
1749 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 if (run_irq_work) {
1752 wl1271_debug(DEBUG_MAC80211,
1753 "run postponed irq_work directly");
1754 wl1271_irq(0, wl);
1755 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001756 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001757 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001758 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001759
Eliad Peller402e48612011-05-13 11:57:09 +03001760 return 0;
1761}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001762#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001763
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764static int wl1271_op_start(struct ieee80211_hw *hw)
1765{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001766 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1767
1768 /*
1769 * We have to delay the booting of the hardware because
1770 * we need to know the local MAC address before downloading and
1771 * initializing the firmware. The MAC address cannot be changed
1772 * after boot, and without the proper MAC address, the firmware
1773 * will not function properly.
1774 *
1775 * The MAC address is first known when the corresponding interface
1776 * is added. That is where we will initialize the hardware.
1777 */
1778
1779 return 0;
1780}
1781
1782static void wl1271_op_stop(struct ieee80211_hw *hw)
1783{
1784 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1785}
1786
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001787static u8 wl12xx_get_role_type(struct wl1271 *wl)
1788{
1789 switch (wl->bss_type) {
1790 case BSS_TYPE_AP_BSS:
1791 return WL1271_ROLE_AP;
1792
1793 case BSS_TYPE_STA_BSS:
1794 return WL1271_ROLE_STA;
1795
Eliad Peller227e81e2011-08-14 13:17:26 +03001796 case BSS_TYPE_IBSS:
1797 return WL1271_ROLE_IBSS;
1798
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001799 default:
1800 wl1271_error("invalid bss_type: %d", wl->bss_type);
1801 }
1802 return WL12XX_INVALID_ROLE_TYPE;
1803}
1804
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001805static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1806 struct ieee80211_vif *vif)
1807{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001809 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001810 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001812 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001813 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001815 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1816 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001817
1818 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001819 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001820 wl1271_debug(DEBUG_MAC80211,
1821 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001822 ret = -EBUSY;
1823 goto out;
1824 }
1825
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001826 /*
1827 * in some very corner case HW recovery scenarios its possible to
1828 * get here before __wl1271_op_remove_interface is complete, so
1829 * opt out if that is the case.
1830 */
1831 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1832 ret = -EBUSY;
1833 goto out;
1834 }
1835
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001836 switch (vif->type) {
1837 case NL80211_IFTYPE_STATION:
1838 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001839 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001840 break;
1841 case NL80211_IFTYPE_ADHOC:
1842 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001843 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001844 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001845 case NL80211_IFTYPE_AP:
1846 wl->bss_type = BSS_TYPE_AP_BSS;
1847 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001848 default:
1849 ret = -EOPNOTSUPP;
1850 goto out;
1851 }
1852
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001853 role_type = wl12xx_get_role_type(wl);
1854 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1855 ret = -EINVAL;
1856 goto out;
1857 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001858 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859
1860 if (wl->state != WL1271_STATE_OFF) {
1861 wl1271_error("cannot start because not in off state: %d",
1862 wl->state);
1863 ret = -EBUSY;
1864 goto out;
1865 }
1866
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001867 while (retries) {
1868 retries--;
1869 ret = wl1271_chip_wakeup(wl);
1870 if (ret < 0)
1871 goto power_off;
1872
1873 ret = wl1271_boot(wl);
1874 if (ret < 0)
1875 goto power_off;
1876
Eliad Peller227e81e2011-08-14 13:17:26 +03001877 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1878 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001879 /*
1880 * The device role is a special role used for
1881 * rx and tx frames prior to association (as
1882 * the STA role can get packets only from
1883 * its associated bssid)
1884 */
1885 ret = wl12xx_cmd_role_enable(wl,
1886 WL1271_ROLE_DEVICE,
1887 &wl->dev_role_id);
1888 if (ret < 0)
1889 goto irq_disable;
1890 }
1891
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001892 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1893 if (ret < 0)
1894 goto irq_disable;
1895
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001896 ret = wl1271_hw_init(wl);
1897 if (ret < 0)
1898 goto irq_disable;
1899
Eliad Peller71125ab2010-10-28 21:46:43 +02001900 booted = true;
1901 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001903irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001904 mutex_unlock(&wl->mutex);
1905 /* Unlocking the mutex in the middle of handling is
1906 inherently unsafe. In this case we deem it safe to do,
1907 because we need to let any possibly pending IRQ out of
1908 the system (and while we are WL1271_STATE_OFF the IRQ
1909 work function will not do anything.) Also, any other
1910 possible concurrent operations will fail due to the
1911 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001912 wl1271_disable_interrupts(wl);
1913 wl1271_flush_deferred_work(wl);
1914 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001915 mutex_lock(&wl->mutex);
1916power_off:
1917 wl1271_power_off(wl);
1918 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919
Eliad Peller71125ab2010-10-28 21:46:43 +02001920 if (!booted) {
1921 wl1271_error("firmware boot failed despite %d retries",
1922 WL1271_BOOT_RETRIES);
1923 goto out;
1924 }
1925
1926 wl->vif = vif;
1927 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001928 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001929 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001930
1931 /* update hw/fw version info in wiphy struct */
1932 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001933 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001934 sizeof(wiphy->fw_version));
1935
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001936 /*
1937 * Now we know if 11a is supported (info from the NVS), so disable
1938 * 11a channels if not supported
1939 */
1940 if (!wl->enable_11a)
1941 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1942
1943 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1944 wl->enable_11a ? "" : "not ");
1945
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001946out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 mutex_unlock(&wl->mutex);
1948
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001949 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001950 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001951 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001952 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 return ret;
1955}
1956
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001957static void __wl1271_op_remove_interface(struct wl1271 *wl,
1958 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001960 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001962 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001964 /* because of hardware recovery, we may get here twice */
1965 if (wl->state != WL1271_STATE_ON)
1966 return;
1967
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001968 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001970 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001971 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001972 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001973
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001974 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001975 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001976 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001977
Luciano Coelho08688d62010-07-08 17:50:07 +03001978 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001979 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001980 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001981 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001982 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983 }
1984
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001985 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1986 /* disable active roles */
1987 ret = wl1271_ps_elp_wakeup(wl);
1988 if (ret < 0)
1989 goto deinit;
1990
Eliad Peller04e80792011-08-14 13:17:09 +03001991 if (wl->bss_type == BSS_TYPE_STA_BSS) {
1992 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
1993 if (ret < 0)
1994 goto deinit;
1995 }
1996
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001997 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
1998 if (ret < 0)
1999 goto deinit;
2000
2001 wl1271_ps_elp_sleep(wl);
2002 }
2003deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002004 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002005 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002006 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002007 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2008 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002009
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002010 /*
2011 * this must be before the cancel_work calls below, so that the work
2012 * functions don't perform further work.
2013 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002014 wl->state = WL1271_STATE_OFF;
2015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 mutex_unlock(&wl->mutex);
2017
Ido Yariva6208652011-03-01 15:14:41 +02002018 wl1271_disable_interrupts(wl);
2019 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002020 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002021 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002023 del_timer_sync(&wl->rx_streaming_timer);
2024 cancel_work_sync(&wl->rx_streaming_enable_work);
2025 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002026 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002027 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028
2029 mutex_lock(&wl->mutex);
2030
2031 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002032 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 wl1271_power_off(wl);
2034
2035 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002036 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002039 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002040 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041
2042 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002043 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2045 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002046 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl->tx_results_count = 0;
2048 wl->tx_packets_count = 0;
2049 wl->time_offset = 0;
2050 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002051 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002052 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002053 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002054 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002055 wl->ap_fw_ps_map = 0;
2056 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002057 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002058 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002059 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002060 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2061 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002062 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002063
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002064 /* The system link is always allocated */
2065 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2066
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002067 /*
2068 * this is performed after the cancel_work calls and the associated
2069 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2070 * get executed before all these vars have been reset.
2071 */
2072 wl->flags = 0;
2073
Eliad Peller4d56ad92011-08-14 13:17:05 +03002074 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075
Arik Nemtsov742246f2011-08-14 13:17:33 +03002076 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002077 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002078 wl->tx_allocated_pkts[i] = 0;
2079 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002082
2083 kfree(wl->fw_status);
2084 wl->fw_status = NULL;
2085 kfree(wl->tx_res_if);
2086 wl->tx_res_if = NULL;
2087 kfree(wl->target_mem_map);
2088 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002089}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002090
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002091static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2092 struct ieee80211_vif *vif)
2093{
2094 struct wl1271 *wl = hw->priv;
2095
2096 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002097 /*
2098 * wl->vif can be null here if someone shuts down the interface
2099 * just when hardware recovery has been started.
2100 */
2101 if (wl->vif) {
2102 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002103 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002104 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002105
Juuso Oikarinen67353292010-11-18 15:19:02 +02002106 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002107 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108}
2109
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002110static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002111{
2112 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002113 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002114
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002115 /*
2116 * One of the side effects of the JOIN command is that is clears
2117 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2118 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002119 * Currently the only valid scenario for JOIN during association
2120 * is on roaming, in which case we will also be given new keys.
2121 * Keep the below message for now, unless it starts bothering
2122 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002123 */
2124 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2125 wl1271_info("JOIN while associated.");
2126
2127 if (set_assoc)
2128 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2129
Eliad Peller227e81e2011-08-14 13:17:26 +03002130 if (is_ibss)
2131 ret = wl12xx_cmd_role_start_ibss(wl);
2132 else
2133 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002134 if (ret < 0)
2135 goto out;
2136
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002137 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2138 goto out;
2139
2140 /*
2141 * The join command disable the keep-alive mode, shut down its process,
2142 * and also clear the template config, so we need to reset it all after
2143 * the join. The acx_aid starts the keep-alive process, and the order
2144 * of the commands below is relevant.
2145 */
2146 ret = wl1271_acx_keep_alive_mode(wl, true);
2147 if (ret < 0)
2148 goto out;
2149
2150 ret = wl1271_acx_aid(wl, wl->aid);
2151 if (ret < 0)
2152 goto out;
2153
2154 ret = wl1271_cmd_build_klv_null_data(wl);
2155 if (ret < 0)
2156 goto out;
2157
2158 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2159 ACX_KEEP_ALIVE_TPL_VALID);
2160 if (ret < 0)
2161 goto out;
2162
2163out:
2164 return ret;
2165}
2166
2167static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002168{
2169 int ret;
2170
2171 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002172 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002173 if (ret < 0)
2174 goto out;
2175
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002176 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002177
Oz Krakowskib992c682011-06-26 10:36:02 +03002178 /* reset TX security counters on a clean disconnect */
2179 wl->tx_security_last_seq_lsb = 0;
2180 wl->tx_security_seq = 0;
2181
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002182out:
2183 return ret;
2184}
2185
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002186static void wl1271_set_band_rate(struct wl1271 *wl)
2187{
2188 if (wl->band == IEEE80211_BAND_2GHZ)
2189 wl->basic_rate_set = wl->conf.tx.basic_rate;
2190 else
2191 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2192}
2193
Eliad Peller251c1772011-08-14 13:17:17 +03002194static bool wl12xx_is_roc(struct wl1271 *wl)
2195{
2196 u8 role_id;
2197
2198 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2199 if (role_id >= WL12XX_MAX_ROLES)
2200 return false;
2201
2202 return true;
2203}
2204
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002205static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002206{
2207 int ret;
2208
2209 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002210 /* no need to croc if we weren't busy (e.g. during boot) */
2211 if (wl12xx_is_roc(wl)) {
2212 ret = wl12xx_croc(wl, wl->dev_role_id);
2213 if (ret < 0)
2214 goto out;
2215
2216 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002217 if (ret < 0)
2218 goto out;
2219 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002220 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002221 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002222 if (ret < 0)
2223 goto out;
2224 ret = wl1271_acx_keep_alive_config(
2225 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2226 ACX_KEEP_ALIVE_TPL_INVALID);
2227 if (ret < 0)
2228 goto out;
2229 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2230 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002231 /* The current firmware only supports sched_scan in idle */
2232 if (wl->sched_scanning) {
2233 wl1271_scan_sched_scan_stop(wl);
2234 ieee80211_sched_scan_stopped(wl->hw);
2235 }
2236
Eliad Peller251c1772011-08-14 13:17:17 +03002237 ret = wl12xx_cmd_role_start_dev(wl);
2238 if (ret < 0)
2239 goto out;
2240
2241 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002242 if (ret < 0)
2243 goto out;
2244 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2245 }
2246
2247out:
2248 return ret;
2249}
2250
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2252{
2253 struct wl1271 *wl = hw->priv;
2254 struct ieee80211_conf *conf = &hw->conf;
2255 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002256 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257
2258 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2259
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002260 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2261 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262 channel,
2263 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002264 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002265 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2266 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002267
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002268 /*
2269 * mac80211 will go to idle nearly immediately after transmitting some
2270 * frames, such as the deauth. To make sure those frames reach the air,
2271 * wait here until the TX queue is fully flushed.
2272 */
2273 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2274 (conf->flags & IEEE80211_CONF_IDLE))
2275 wl1271_tx_flush(wl);
2276
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002277 mutex_lock(&wl->mutex);
2278
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002279 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002280 /* we support configuring the channel and band while off */
2281 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2282 wl->band = conf->channel->band;
2283 wl->channel = channel;
2284 }
2285
Arik Nemtsov097f8822011-06-27 22:06:34 +03002286 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2287 wl->power_level = conf->power_level;
2288
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002289 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002290 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002291
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002292 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2293
Ido Yariva6208652011-03-01 15:14:41 +02002294 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295 if (ret < 0)
2296 goto out;
2297
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002298 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002299 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2300 ((wl->band != conf->channel->band) ||
2301 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002302 wl->band = conf->channel->band;
2303 wl->channel = channel;
2304
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002305 if (!is_ap) {
2306 /*
2307 * FIXME: the mac80211 should really provide a fixed
2308 * rate to use here. for now, just use the smallest
2309 * possible rate for the band as a fixed rate for
2310 * association frames and other control messages.
2311 */
2312 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2313 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002314
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002315 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2316 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002317 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002318 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002319 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002320
Eliad Peller251c1772011-08-14 13:17:17 +03002321 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2322 if (wl12xx_is_roc(wl)) {
2323 /* roaming */
2324 ret = wl12xx_croc(wl, wl->dev_role_id);
2325 if (ret < 0)
2326 goto out_sleep;
2327 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002328 ret = wl1271_join(wl, false);
2329 if (ret < 0)
2330 wl1271_warning("cmd join on channel "
2331 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002332 } else {
2333 /*
2334 * change the ROC channel. do it only if we are
2335 * not idle. otherwise, CROC will be called
2336 * anyway.
2337 */
2338 if (wl12xx_is_roc(wl) &&
2339 !(conf->flags & IEEE80211_CONF_IDLE)) {
2340 ret = wl12xx_croc(wl, wl->dev_role_id);
2341 if (ret < 0)
2342 goto out_sleep;
2343
2344 ret = wl12xx_roc(wl, wl->dev_role_id);
2345 if (ret < 0)
2346 wl1271_warning("roc failed %d",
2347 ret);
2348 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002349 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002350 }
2351 }
2352
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002353 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2354 ret = wl1271_sta_handle_idle(wl,
2355 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002356 if (ret < 0)
2357 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 }
2359
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002360 /*
2361 * if mac80211 changes the PSM mode, make sure the mode is not
2362 * incorrectly changed after the pspoll failure active window.
2363 */
2364 if (changed & IEEE80211_CONF_CHANGE_PS)
2365 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2366
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002367 if (conf->flags & IEEE80211_CONF_PS &&
2368 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2369 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370
2371 /*
2372 * We enter PSM only if we're already associated.
2373 * If we're not, we'll enter it when joining an SSID,
2374 * through the bss_info_changed() hook.
2375 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002376 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002377 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002378 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002379 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002380 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002381 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002382 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002383 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002385 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002387 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002388 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002389 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 }
2391
2392 if (conf->power_level != wl->power_level) {
2393 ret = wl1271_acx_tx_power(wl, conf->power_level);
2394 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002395 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396
2397 wl->power_level = conf->power_level;
2398 }
2399
2400out_sleep:
2401 wl1271_ps_elp_sleep(wl);
2402
2403out:
2404 mutex_unlock(&wl->mutex);
2405
2406 return ret;
2407}
2408
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002409struct wl1271_filter_params {
2410 bool enabled;
2411 int mc_list_length;
2412 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2413};
2414
Jiri Pirko22bedad2010-04-01 21:22:57 +00002415static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2416 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002417{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002418 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002419 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002420 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002421
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002422 if (unlikely(wl->state == WL1271_STATE_OFF))
2423 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002424
Juuso Oikarinen74441132009-10-13 12:47:53 +03002425 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002426 if (!fp) {
2427 wl1271_error("Out of memory setting filters.");
2428 return 0;
2429 }
2430
2431 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002432 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002433 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2434 fp->enabled = false;
2435 } else {
2436 fp->enabled = true;
2437 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002438 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002439 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002440 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002441 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002442 }
2443
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002444 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002445}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002446
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002447#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2448 FIF_ALLMULTI | \
2449 FIF_FCSFAIL | \
2450 FIF_BCN_PRBRESP_PROMISC | \
2451 FIF_CONTROL | \
2452 FIF_OTHER_BSS)
2453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2455 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002456 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002458 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002459 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002460 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461
Arik Nemtsov7d057862010-10-16 19:25:35 +02002462 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2463 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002465 mutex_lock(&wl->mutex);
2466
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002467 *total &= WL1271_SUPPORTED_FILTERS;
2468 changed &= WL1271_SUPPORTED_FILTERS;
2469
2470 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002471 goto out;
2472
Ido Yariva6208652011-03-01 15:14:41 +02002473 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002474 if (ret < 0)
2475 goto out;
2476
Arik Nemtsov7d057862010-10-16 19:25:35 +02002477 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2478 if (*total & FIF_ALLMULTI)
2479 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2480 else if (fp)
2481 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2482 fp->mc_list,
2483 fp->mc_list_length);
2484 if (ret < 0)
2485 goto out_sleep;
2486 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002487
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002488 /*
2489 * the fw doesn't provide an api to configure the filters. instead,
2490 * the filters configuration is based on the active roles / ROC
2491 * state.
2492 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002493
2494out_sleep:
2495 wl1271_ps_elp_sleep(wl);
2496
2497out:
2498 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002499 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002500}
2501
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002502static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2503 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2504 u16 tx_seq_16)
2505{
2506 struct wl1271_ap_key *ap_key;
2507 int i;
2508
2509 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2510
2511 if (key_size > MAX_KEY_SIZE)
2512 return -EINVAL;
2513
2514 /*
2515 * Find next free entry in ap_keys. Also check we are not replacing
2516 * an existing key.
2517 */
2518 for (i = 0; i < MAX_NUM_KEYS; i++) {
2519 if (wl->recorded_ap_keys[i] == NULL)
2520 break;
2521
2522 if (wl->recorded_ap_keys[i]->id == id) {
2523 wl1271_warning("trying to record key replacement");
2524 return -EINVAL;
2525 }
2526 }
2527
2528 if (i == MAX_NUM_KEYS)
2529 return -EBUSY;
2530
2531 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2532 if (!ap_key)
2533 return -ENOMEM;
2534
2535 ap_key->id = id;
2536 ap_key->key_type = key_type;
2537 ap_key->key_size = key_size;
2538 memcpy(ap_key->key, key, key_size);
2539 ap_key->hlid = hlid;
2540 ap_key->tx_seq_32 = tx_seq_32;
2541 ap_key->tx_seq_16 = tx_seq_16;
2542
2543 wl->recorded_ap_keys[i] = ap_key;
2544 return 0;
2545}
2546
2547static void wl1271_free_ap_keys(struct wl1271 *wl)
2548{
2549 int i;
2550
2551 for (i = 0; i < MAX_NUM_KEYS; i++) {
2552 kfree(wl->recorded_ap_keys[i]);
2553 wl->recorded_ap_keys[i] = NULL;
2554 }
2555}
2556
2557static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2558{
2559 int i, ret = 0;
2560 struct wl1271_ap_key *key;
2561 bool wep_key_added = false;
2562
2563 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002564 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002565 if (wl->recorded_ap_keys[i] == NULL)
2566 break;
2567
2568 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002569 hlid = key->hlid;
2570 if (hlid == WL12XX_INVALID_LINK_ID)
2571 hlid = wl->ap_bcast_hlid;
2572
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002573 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2574 key->id, key->key_type,
2575 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002576 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002577 key->tx_seq_16);
2578 if (ret < 0)
2579 goto out;
2580
2581 if (key->key_type == KEY_WEP)
2582 wep_key_added = true;
2583 }
2584
2585 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002586 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002587 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002588 if (ret < 0)
2589 goto out;
2590 }
2591
2592out:
2593 wl1271_free_ap_keys(wl);
2594 return ret;
2595}
2596
2597static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2598 u8 key_size, const u8 *key, u32 tx_seq_32,
2599 u16 tx_seq_16, struct ieee80211_sta *sta)
2600{
2601 int ret;
2602 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2603
2604 if (is_ap) {
2605 struct wl1271_station *wl_sta;
2606 u8 hlid;
2607
2608 if (sta) {
2609 wl_sta = (struct wl1271_station *)sta->drv_priv;
2610 hlid = wl_sta->hlid;
2611 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002612 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002613 }
2614
2615 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2616 /*
2617 * We do not support removing keys after AP shutdown.
2618 * Pretend we do to make mac80211 happy.
2619 */
2620 if (action != KEY_ADD_OR_REPLACE)
2621 return 0;
2622
2623 ret = wl1271_record_ap_key(wl, id,
2624 key_type, key_size,
2625 key, hlid, tx_seq_32,
2626 tx_seq_16);
2627 } else {
2628 ret = wl1271_cmd_set_ap_key(wl, action,
2629 id, key_type, key_size,
2630 key, hlid, tx_seq_32,
2631 tx_seq_16);
2632 }
2633
2634 if (ret < 0)
2635 return ret;
2636 } else {
2637 const u8 *addr;
2638 static const u8 bcast_addr[ETH_ALEN] = {
2639 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2640 };
2641
2642 addr = sta ? sta->addr : bcast_addr;
2643
2644 if (is_zero_ether_addr(addr)) {
2645 /* We dont support TX only encryption */
2646 return -EOPNOTSUPP;
2647 }
2648
2649 /* The wl1271 does not allow to remove unicast keys - they
2650 will be cleared automatically on next CMD_JOIN. Ignore the
2651 request silently, as we dont want the mac80211 to emit
2652 an error message. */
2653 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2654 return 0;
2655
Eliad Peller010d3d32011-08-14 13:17:31 +03002656 /* don't remove key if hlid was already deleted */
2657 if (action == KEY_REMOVE &&
2658 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2659 return 0;
2660
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002661 ret = wl1271_cmd_set_sta_key(wl, action,
2662 id, key_type, key_size,
2663 key, addr, tx_seq_32,
2664 tx_seq_16);
2665 if (ret < 0)
2666 return ret;
2667
2668 /* the default WEP key needs to be configured at least once */
2669 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002670 ret = wl12xx_cmd_set_default_wep_key(wl,
2671 wl->default_key,
2672 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002673 if (ret < 0)
2674 return ret;
2675 }
2676 }
2677
2678 return 0;
2679}
2680
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2682 struct ieee80211_vif *vif,
2683 struct ieee80211_sta *sta,
2684 struct ieee80211_key_conf *key_conf)
2685{
2686 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002688 u32 tx_seq_32 = 0;
2689 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690 u8 key_type;
2691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2693
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002694 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002695 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002696 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697 key_conf->keylen, key_conf->flags);
2698 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2699
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002700 mutex_lock(&wl->mutex);
2701
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002702 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2703 ret = -EAGAIN;
2704 goto out_unlock;
2705 }
2706
Ido Yariva6208652011-03-01 15:14:41 +02002707 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708 if (ret < 0)
2709 goto out_unlock;
2710
Johannes Berg97359d12010-08-10 09:46:38 +02002711 switch (key_conf->cipher) {
2712 case WLAN_CIPHER_SUITE_WEP40:
2713 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002714 key_type = KEY_WEP;
2715
2716 key_conf->hw_key_idx = key_conf->keyidx;
2717 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002718 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719 key_type = KEY_TKIP;
2720
2721 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002722 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2723 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002725 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002726 key_type = KEY_AES;
2727
2728 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002729 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2730 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002732 case WL1271_CIPHER_SUITE_GEM:
2733 key_type = KEY_GEM;
2734 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2735 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2736 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002738 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002739
2740 ret = -EOPNOTSUPP;
2741 goto out_sleep;
2742 }
2743
2744 switch (cmd) {
2745 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002746 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2747 key_conf->keyidx, key_type,
2748 key_conf->keylen, key_conf->key,
2749 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002750 if (ret < 0) {
2751 wl1271_error("Could not add or replace key");
2752 goto out_sleep;
2753 }
2754 break;
2755
2756 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002757 ret = wl1271_set_key(wl, KEY_REMOVE,
2758 key_conf->keyidx, key_type,
2759 key_conf->keylen, key_conf->key,
2760 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761 if (ret < 0) {
2762 wl1271_error("Could not remove key");
2763 goto out_sleep;
2764 }
2765 break;
2766
2767 default:
2768 wl1271_error("Unsupported key cmd 0x%x", cmd);
2769 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002770 break;
2771 }
2772
2773out_sleep:
2774 wl1271_ps_elp_sleep(wl);
2775
2776out_unlock:
2777 mutex_unlock(&wl->mutex);
2778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002779 return ret;
2780}
2781
2782static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002783 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002784 struct cfg80211_scan_request *req)
2785{
2786 struct wl1271 *wl = hw->priv;
2787 int ret;
2788 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002789 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790
2791 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2792
2793 if (req->n_ssids) {
2794 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002795 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002796 }
2797
2798 mutex_lock(&wl->mutex);
2799
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002800 if (wl->state == WL1271_STATE_OFF) {
2801 /*
2802 * We cannot return -EBUSY here because cfg80211 will expect
2803 * a call to ieee80211_scan_completed if we do - in this case
2804 * there won't be any call.
2805 */
2806 ret = -EAGAIN;
2807 goto out;
2808 }
2809
Ido Yariva6208652011-03-01 15:14:41 +02002810 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 if (ret < 0)
2812 goto out;
2813
Eliad Peller251c1772011-08-14 13:17:17 +03002814 /* cancel ROC before scanning */
2815 if (wl12xx_is_roc(wl)) {
2816 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2817 /* don't allow scanning right now */
2818 ret = -EBUSY;
2819 goto out_sleep;
2820 }
2821 wl12xx_croc(wl, wl->dev_role_id);
2822 wl12xx_cmd_role_stop_dev(wl);
2823 }
2824
Luciano Coelho5924f892010-08-04 03:46:22 +03002825 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002826out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828out:
2829 mutex_unlock(&wl->mutex);
2830
2831 return ret;
2832}
2833
Eliad Peller73ecce32011-06-27 13:06:45 +03002834static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2835 struct ieee80211_vif *vif)
2836{
2837 struct wl1271 *wl = hw->priv;
2838 int ret;
2839
2840 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2841
2842 mutex_lock(&wl->mutex);
2843
2844 if (wl->state == WL1271_STATE_OFF)
2845 goto out;
2846
2847 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2848 goto out;
2849
2850 ret = wl1271_ps_elp_wakeup(wl);
2851 if (ret < 0)
2852 goto out;
2853
2854 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2855 ret = wl1271_scan_stop(wl);
2856 if (ret < 0)
2857 goto out_sleep;
2858 }
2859 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2860 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2861 wl->scan.req = NULL;
2862 ieee80211_scan_completed(wl->hw, true);
2863
2864out_sleep:
2865 wl1271_ps_elp_sleep(wl);
2866out:
2867 mutex_unlock(&wl->mutex);
2868
2869 cancel_delayed_work_sync(&wl->scan_complete_work);
2870}
2871
Luciano Coelho33c2c062011-05-10 14:46:02 +03002872static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2873 struct ieee80211_vif *vif,
2874 struct cfg80211_sched_scan_request *req,
2875 struct ieee80211_sched_scan_ies *ies)
2876{
2877 struct wl1271 *wl = hw->priv;
2878 int ret;
2879
2880 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2881
2882 mutex_lock(&wl->mutex);
2883
2884 ret = wl1271_ps_elp_wakeup(wl);
2885 if (ret < 0)
2886 goto out;
2887
2888 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2889 if (ret < 0)
2890 goto out_sleep;
2891
2892 ret = wl1271_scan_sched_scan_start(wl);
2893 if (ret < 0)
2894 goto out_sleep;
2895
2896 wl->sched_scanning = true;
2897
2898out_sleep:
2899 wl1271_ps_elp_sleep(wl);
2900out:
2901 mutex_unlock(&wl->mutex);
2902 return ret;
2903}
2904
2905static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2906 struct ieee80211_vif *vif)
2907{
2908 struct wl1271 *wl = hw->priv;
2909 int ret;
2910
2911 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2912
2913 mutex_lock(&wl->mutex);
2914
2915 ret = wl1271_ps_elp_wakeup(wl);
2916 if (ret < 0)
2917 goto out;
2918
2919 wl1271_scan_sched_scan_stop(wl);
2920
2921 wl1271_ps_elp_sleep(wl);
2922out:
2923 mutex_unlock(&wl->mutex);
2924}
2925
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002926static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2927{
2928 struct wl1271 *wl = hw->priv;
2929 int ret = 0;
2930
2931 mutex_lock(&wl->mutex);
2932
2933 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2934 ret = -EAGAIN;
2935 goto out;
2936 }
2937
Ido Yariva6208652011-03-01 15:14:41 +02002938 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002939 if (ret < 0)
2940 goto out;
2941
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002942 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002943 if (ret < 0)
2944 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2945
2946 wl1271_ps_elp_sleep(wl);
2947
2948out:
2949 mutex_unlock(&wl->mutex);
2950
2951 return ret;
2952}
2953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2955{
2956 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002957 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958
2959 mutex_lock(&wl->mutex);
2960
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002961 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2962 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002963 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002964 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002965
Ido Yariva6208652011-03-01 15:14:41 +02002966 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 if (ret < 0)
2968 goto out;
2969
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002970 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 if (ret < 0)
2972 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2973
2974 wl1271_ps_elp_sleep(wl);
2975
2976out:
2977 mutex_unlock(&wl->mutex);
2978
2979 return ret;
2980}
2981
Arik Nemtsove78a2872010-10-16 19:07:21 +02002982static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002983 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002984{
Eliad Peller889cb362011-05-01 09:56:45 +03002985 u8 ssid_len;
2986 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2987 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002988
Eliad Peller889cb362011-05-01 09:56:45 +03002989 if (!ptr) {
2990 wl1271_error("No SSID in IEs!");
2991 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002992 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002993
Eliad Peller889cb362011-05-01 09:56:45 +03002994 ssid_len = ptr[1];
2995 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2996 wl1271_error("SSID is too long!");
2997 return -EINVAL;
2998 }
2999
3000 wl->ssid_len = ssid_len;
3001 memcpy(wl->ssid, ptr+2, ssid_len);
3002 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003003}
3004
Arik Nemtsove78a2872010-10-16 19:07:21 +02003005static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3006 struct ieee80211_bss_conf *bss_conf,
3007 u32 changed)
3008{
3009 int ret = 0;
3010
3011 if (changed & BSS_CHANGED_ERP_SLOT) {
3012 if (bss_conf->use_short_slot)
3013 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3014 else
3015 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3016 if (ret < 0) {
3017 wl1271_warning("Set slot time failed %d", ret);
3018 goto out;
3019 }
3020 }
3021
3022 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3023 if (bss_conf->use_short_preamble)
3024 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3025 else
3026 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3027 }
3028
3029 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3030 if (bss_conf->use_cts_prot)
3031 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3032 else
3033 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3034 if (ret < 0) {
3035 wl1271_warning("Set ctsprotect failed %d", ret);
3036 goto out;
3037 }
3038 }
3039
3040out:
3041 return ret;
3042}
3043
3044static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3045 struct ieee80211_vif *vif,
3046 struct ieee80211_bss_conf *bss_conf,
3047 u32 changed)
3048{
3049 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3050 int ret = 0;
3051
3052 if ((changed & BSS_CHANGED_BEACON_INT)) {
3053 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3054 bss_conf->beacon_int);
3055
3056 wl->beacon_int = bss_conf->beacon_int;
3057 }
3058
3059 if ((changed & BSS_CHANGED_BEACON)) {
3060 struct ieee80211_hdr *hdr;
3061 int ieoffset = offsetof(struct ieee80211_mgmt,
3062 u.beacon.variable);
3063 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3064 u16 tmpl_id;
3065
3066 if (!beacon)
3067 goto out;
3068
3069 wl1271_debug(DEBUG_MASTER, "beacon updated");
3070
3071 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3072 if (ret < 0) {
3073 dev_kfree_skb(beacon);
3074 goto out;
3075 }
3076 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3077 CMD_TEMPL_BEACON;
3078 ret = wl1271_cmd_template_set(wl, tmpl_id,
3079 beacon->data,
3080 beacon->len, 0,
3081 wl1271_tx_min_rate_get(wl));
3082 if (ret < 0) {
3083 dev_kfree_skb(beacon);
3084 goto out;
3085 }
3086
3087 hdr = (struct ieee80211_hdr *) beacon->data;
3088 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3089 IEEE80211_STYPE_PROBE_RESP);
3090
3091 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3092 CMD_TEMPL_PROBE_RESPONSE;
3093 ret = wl1271_cmd_template_set(wl,
3094 tmpl_id,
3095 beacon->data,
3096 beacon->len, 0,
3097 wl1271_tx_min_rate_get(wl));
3098 dev_kfree_skb(beacon);
3099 if (ret < 0)
3100 goto out;
3101 }
3102
3103out:
3104 return ret;
3105}
3106
3107/* AP mode changes */
3108static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109 struct ieee80211_vif *vif,
3110 struct ieee80211_bss_conf *bss_conf,
3111 u32 changed)
3112{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003113 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114
Arik Nemtsove78a2872010-10-16 19:07:21 +02003115 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3116 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003117
Arik Nemtsove78a2872010-10-16 19:07:21 +02003118 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3119 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003120
Arik Nemtsov70f47422011-04-18 14:15:25 +03003121 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003122 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003123 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003124 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003125 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003126
3127 ret = wl1271_ap_init_templates(wl);
3128 if (ret < 0)
3129 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003130 }
3131
Arik Nemtsove78a2872010-10-16 19:07:21 +02003132 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3133 if (ret < 0)
3134 goto out;
3135
3136 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3137 if (bss_conf->enable_beacon) {
3138 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003139 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003140 if (ret < 0)
3141 goto out;
3142
3143 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3144 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003145
3146 ret = wl1271_ap_init_hwenc(wl);
3147 if (ret < 0)
3148 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003149 }
3150 } else {
3151 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003152 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003153 if (ret < 0)
3154 goto out;
3155
3156 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3157 wl1271_debug(DEBUG_AP, "stopped AP");
3158 }
3159 }
3160 }
3161
3162 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3163 if (ret < 0)
3164 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003165
3166 /* Handle HT information change */
3167 if ((changed & BSS_CHANGED_HT) &&
3168 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3169 ret = wl1271_acx_set_ht_information(wl,
3170 bss_conf->ht_operation_mode);
3171 if (ret < 0) {
3172 wl1271_warning("Set ht information failed %d", ret);
3173 goto out;
3174 }
3175 }
3176
Arik Nemtsove78a2872010-10-16 19:07:21 +02003177out:
3178 return;
3179}
3180
3181/* STA/IBSS mode changes */
3182static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3183 struct ieee80211_vif *vif,
3184 struct ieee80211_bss_conf *bss_conf,
3185 u32 changed)
3186{
3187 bool do_join = false, set_assoc = false;
3188 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003189 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003190 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003191 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003192 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003193 bool sta_exists = false;
3194 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003195
3196 if (is_ibss) {
3197 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3198 changed);
3199 if (ret < 0)
3200 goto out;
3201 }
3202
Eliad Peller227e81e2011-08-14 13:17:26 +03003203 if (changed & BSS_CHANGED_IBSS) {
3204 if (bss_conf->ibss_joined) {
3205 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3206 ibss_joined = true;
3207 } else {
3208 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3209 &wl->flags)) {
3210 wl1271_unjoin(wl);
3211 wl12xx_cmd_role_start_dev(wl);
3212 wl12xx_roc(wl, wl->dev_role_id);
3213 }
3214 }
3215 }
3216
3217 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003218 do_join = true;
3219
3220 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003221 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003222 do_join = true;
3223
Eliad Peller227e81e2011-08-14 13:17:26 +03003224 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003225 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3226 bss_conf->enable_beacon ? "enabled" : "disabled");
3227
3228 if (bss_conf->enable_beacon)
3229 wl->set_bss_type = BSS_TYPE_IBSS;
3230 else
3231 wl->set_bss_type = BSS_TYPE_STA_BSS;
3232 do_join = true;
3233 }
3234
Arik Nemtsove78a2872010-10-16 19:07:21 +02003235 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003236 bool enable = false;
3237 if (bss_conf->cqm_rssi_thold)
3238 enable = true;
3239 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3240 bss_conf->cqm_rssi_thold,
3241 bss_conf->cqm_rssi_hyst);
3242 if (ret < 0)
3243 goto out;
3244 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3245 }
3246
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003247 if ((changed & BSS_CHANGED_BSSID) &&
3248 /*
3249 * Now we know the correct bssid, so we send a new join command
3250 * and enable the BSSID filter
3251 */
3252 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003253 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003254
Eliad Pellerfa287b82010-12-26 09:27:50 +01003255 if (!is_zero_ether_addr(wl->bssid)) {
3256 ret = wl1271_cmd_build_null_data(wl);
3257 if (ret < 0)
3258 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003259
Eliad Pellerfa287b82010-12-26 09:27:50 +01003260 ret = wl1271_build_qos_null_data(wl);
3261 if (ret < 0)
3262 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003263
Eliad Pellerfa287b82010-12-26 09:27:50 +01003264 /* Need to update the BSSID (for filtering etc) */
3265 do_join = true;
3266 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003267 }
3268
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003269 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3270 rcu_read_lock();
3271 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3272 if (!sta)
3273 goto sta_not_found;
3274
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003275 /* save the supp_rates of the ap */
3276 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3277 if (sta->ht_cap.ht_supported)
3278 sta_rate_set |=
3279 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003280 sta_ht_cap = sta->ht_cap;
3281 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003282
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003283sta_not_found:
3284 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003285 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003286
Arik Nemtsove78a2872010-10-16 19:07:21 +02003287 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003288 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003289 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003290 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003291 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003292 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003293
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003294 wl->ps_poll_failures = 0;
3295
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003296 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003297 * use basic rates from AP, and determine lowest rate
3298 * to use with control frames.
3299 */
3300 rates = bss_conf->basic_rates;
3301 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3302 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003303 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003304 if (sta_rate_set)
3305 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3306 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003307 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003308 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003309 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003310
3311 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003312 * with wl1271, we don't need to update the
3313 * beacon_int and dtim_period, because the firmware
3314 * updates it by itself when the first beacon is
3315 * received after a join.
3316 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003317 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3318 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003319 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003320
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003321 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003322 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003323 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003324 dev_kfree_skb(wl->probereq);
3325 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3326 ieoffset = offsetof(struct ieee80211_mgmt,
3327 u.probe_req.variable);
3328 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003329
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003330 /* enable the connection monitoring feature */
3331 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003332 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003334
3335 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003336 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3337 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003338 enum wl1271_cmd_ps_mode mode;
3339
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003341 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003342 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003343 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003344 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003347 } else {
3348 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003349 bool was_assoc =
3350 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3351 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003352 bool was_ifup =
3353 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3354 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003355 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003356
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003357 /* free probe-request template */
3358 dev_kfree_skb(wl->probereq);
3359 wl->probereq = NULL;
3360
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003361 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003362 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003363
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003364 /* revert back to minimum rates for the current band */
3365 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003366 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003367 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003368 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003369 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003370
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003371 /* disable connection monitor features */
3372 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003373
3374 /* Disable the keep-alive feature */
3375 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003376 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003378
3379 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003380 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003381 u32 conf_flags = wl->hw->conf.flags;
3382 /*
3383 * we might have to disable roc, if there was
3384 * no IF_OPER_UP notification.
3385 */
3386 if (!was_ifup) {
3387 ret = wl12xx_croc(wl, wl->role_id);
3388 if (ret < 0)
3389 goto out;
3390 }
3391 /*
3392 * (we also need to disable roc in case of
3393 * roaming on the same channel. until we will
3394 * have a better flow...)
3395 */
3396 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3397 ret = wl12xx_croc(wl, wl->dev_role_id);
3398 if (ret < 0)
3399 goto out;
3400 }
3401
Eliad Peller30df14d2011-04-05 19:13:28 +03003402 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003403 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3404 wl12xx_cmd_role_start_dev(wl);
3405 wl12xx_roc(wl, wl->dev_role_id);
3406 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003407 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003408 }
3409 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003410
Eliad Pellerd192d262011-05-24 14:33:08 +03003411 if (changed & BSS_CHANGED_IBSS) {
3412 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3413 bss_conf->ibss_joined);
3414
3415 if (bss_conf->ibss_joined) {
3416 u32 rates = bss_conf->basic_rates;
3417 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3418 rates);
3419 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3420
3421 /* by default, use 11b rates */
3422 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3423 ret = wl1271_acx_sta_rate_policies(wl);
3424 if (ret < 0)
3425 goto out;
3426 }
3427 }
3428
Arik Nemtsove78a2872010-10-16 19:07:21 +02003429 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3430 if (ret < 0)
3431 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003432
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003433 if (changed & BSS_CHANGED_ARP_FILTER) {
3434 __be32 addr = bss_conf->arp_addr_list[0];
3435 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3436
Eliad Pellerc5312772010-12-09 11:31:27 +02003437 if (bss_conf->arp_addr_cnt == 1 &&
3438 bss_conf->arp_filter_enabled) {
3439 /*
3440 * The template should have been configured only upon
3441 * association. however, it seems that the correct ip
3442 * isn't being set (when sending), so we have to
3443 * reconfigure the template upon every ip change.
3444 */
3445 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3446 if (ret < 0) {
3447 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003449 }
3450
3451 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003452 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003453 addr);
3454 } else
3455 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003456
3457 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003459 }
3460
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003461 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003462 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003463 if (ret < 0) {
3464 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003465 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003466 }
Eliad Peller251c1772011-08-14 13:17:17 +03003467
3468 /* ROC until connected (after EAPOL exchange) */
3469 if (!is_ibss) {
3470 ret = wl12xx_roc(wl, wl->role_id);
3471 if (ret < 0)
3472 goto out;
3473
3474 wl1271_check_operstate(wl,
3475 ieee80211_get_operstate(vif));
3476 }
3477 /*
3478 * stop device role if started (we might already be in
3479 * STA role). TODO: make it better.
3480 */
3481 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3482 ret = wl12xx_croc(wl, wl->dev_role_id);
3483 if (ret < 0)
3484 goto out;
3485
3486 ret = wl12xx_cmd_role_stop_dev(wl);
3487 if (ret < 0)
3488 goto out;
3489 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003490 }
3491
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003492 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003493 if (sta_exists) {
3494 if ((changed & BSS_CHANGED_HT) &&
3495 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003496 ret = wl1271_acx_set_ht_capabilities(wl,
3497 &sta_ht_cap,
3498 true,
3499 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003500 if (ret < 0) {
3501 wl1271_warning("Set ht cap true failed %d",
3502 ret);
3503 goto out;
3504 }
3505 }
3506 /* handle new association without HT and disassociation */
3507 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003508 ret = wl1271_acx_set_ht_capabilities(wl,
3509 &sta_ht_cap,
3510 false,
3511 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003512 if (ret < 0) {
3513 wl1271_warning("Set ht cap false failed %d",
3514 ret);
3515 goto out;
3516 }
3517 }
3518 }
3519
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003520 /* Handle HT information change. Done after join. */
3521 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003522 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3523 ret = wl1271_acx_set_ht_information(wl,
3524 bss_conf->ht_operation_mode);
3525 if (ret < 0) {
3526 wl1271_warning("Set ht information failed %d", ret);
3527 goto out;
3528 }
3529 }
3530
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531out:
3532 return;
3533}
3534
3535static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3536 struct ieee80211_vif *vif,
3537 struct ieee80211_bss_conf *bss_conf,
3538 u32 changed)
3539{
3540 struct wl1271 *wl = hw->priv;
3541 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3542 int ret;
3543
3544 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3545 (int)changed);
3546
3547 mutex_lock(&wl->mutex);
3548
3549 if (unlikely(wl->state == WL1271_STATE_OFF))
3550 goto out;
3551
Ido Yariva6208652011-03-01 15:14:41 +02003552 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003553 if (ret < 0)
3554 goto out;
3555
3556 if (is_ap)
3557 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3558 else
3559 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3560
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003561 wl1271_ps_elp_sleep(wl);
3562
3563out:
3564 mutex_unlock(&wl->mutex);
3565}
3566
Kalle Valoc6999d82010-02-18 13:25:41 +02003567static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3568 const struct ieee80211_tx_queue_params *params)
3569{
3570 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003571 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003572 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003573
3574 mutex_lock(&wl->mutex);
3575
3576 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3577
Kalle Valo4695dc92010-03-18 12:26:38 +02003578 if (params->uapsd)
3579 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3580 else
3581 ps_scheme = CONF_PS_SCHEME_LEGACY;
3582
Arik Nemtsov488fc542010-10-16 20:33:45 +02003583 if (wl->state == WL1271_STATE_OFF) {
3584 /*
3585 * If the state is off, the parameters will be recorded and
3586 * configured on init. This happens in AP-mode.
3587 */
3588 struct conf_tx_ac_category *conf_ac =
3589 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3590 struct conf_tx_tid *conf_tid =
3591 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3592
3593 conf_ac->ac = wl1271_tx_get_queue(queue);
3594 conf_ac->cw_min = (u8)params->cw_min;
3595 conf_ac->cw_max = params->cw_max;
3596 conf_ac->aifsn = params->aifs;
3597 conf_ac->tx_op_limit = params->txop << 5;
3598
3599 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3600 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3601 conf_tid->tsid = wl1271_tx_get_queue(queue);
3602 conf_tid->ps_scheme = ps_scheme;
3603 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3604 conf_tid->apsd_conf[0] = 0;
3605 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003606 goto out;
3607 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003608
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003609 ret = wl1271_ps_elp_wakeup(wl);
3610 if (ret < 0)
3611 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003612
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003613 /*
3614 * the txop is confed in units of 32us by the mac80211,
3615 * we need us
3616 */
3617 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3618 params->cw_min, params->cw_max,
3619 params->aifs, params->txop << 5);
3620 if (ret < 0)
3621 goto out_sleep;
3622
3623 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3624 CONF_CHANNEL_TYPE_EDCF,
3625 wl1271_tx_get_queue(queue),
3626 ps_scheme, CONF_ACK_POLICY_LEGACY,
3627 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003628
3629out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003630 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003631
3632out:
3633 mutex_unlock(&wl->mutex);
3634
3635 return ret;
3636}
3637
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003638static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3639{
3640
3641 struct wl1271 *wl = hw->priv;
3642 u64 mactime = ULLONG_MAX;
3643 int ret;
3644
3645 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3646
3647 mutex_lock(&wl->mutex);
3648
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003649 if (unlikely(wl->state == WL1271_STATE_OFF))
3650 goto out;
3651
Ido Yariva6208652011-03-01 15:14:41 +02003652 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003653 if (ret < 0)
3654 goto out;
3655
3656 ret = wl1271_acx_tsf_info(wl, &mactime);
3657 if (ret < 0)
3658 goto out_sleep;
3659
3660out_sleep:
3661 wl1271_ps_elp_sleep(wl);
3662
3663out:
3664 mutex_unlock(&wl->mutex);
3665 return mactime;
3666}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667
John W. Linvilleece550d2010-07-28 16:41:06 -04003668static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3669 struct survey_info *survey)
3670{
3671 struct wl1271 *wl = hw->priv;
3672 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003673
John W. Linvilleece550d2010-07-28 16:41:06 -04003674 if (idx != 0)
3675 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003676
John W. Linvilleece550d2010-07-28 16:41:06 -04003677 survey->channel = conf->channel;
3678 survey->filled = SURVEY_INFO_NOISE_DBM;
3679 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003680
John W. Linvilleece550d2010-07-28 16:41:06 -04003681 return 0;
3682}
3683
Arik Nemtsov409622e2011-02-23 00:22:29 +02003684static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003685 struct ieee80211_sta *sta,
3686 u8 *hlid)
3687{
3688 struct wl1271_station *wl_sta;
3689 int id;
3690
3691 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3692 if (id >= AP_MAX_STATIONS) {
3693 wl1271_warning("could not allocate HLID - too much stations");
3694 return -EBUSY;
3695 }
3696
3697 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003698 __set_bit(id, wl->ap_hlid_map);
3699 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3700 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003701 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003702 return 0;
3703}
3704
Arik Nemtsov409622e2011-02-23 00:22:29 +02003705static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003706{
3707 int id = hlid - WL1271_AP_STA_HLID_START;
3708
Arik Nemtsov409622e2011-02-23 00:22:29 +02003709 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3710 return;
3711
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003712 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003713 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003714 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003715 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003716 __clear_bit(hlid, &wl->ap_ps_map);
3717 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003718}
3719
3720static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3721 struct ieee80211_vif *vif,
3722 struct ieee80211_sta *sta)
3723{
3724 struct wl1271 *wl = hw->priv;
3725 int ret = 0;
3726 u8 hlid;
3727
3728 mutex_lock(&wl->mutex);
3729
3730 if (unlikely(wl->state == WL1271_STATE_OFF))
3731 goto out;
3732
3733 if (wl->bss_type != BSS_TYPE_AP_BSS)
3734 goto out;
3735
3736 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3737
Arik Nemtsov409622e2011-02-23 00:22:29 +02003738 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003739 if (ret < 0)
3740 goto out;
3741
Ido Yariva6208652011-03-01 15:14:41 +02003742 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003743 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003744 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003745
Eliad Pellerc690ec82011-08-14 13:17:07 +03003746 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003747 if (ret < 0)
3748 goto out_sleep;
3749
Eliad Pellerb67476e2011-08-14 13:17:23 +03003750 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3751 if (ret < 0)
3752 goto out_sleep;
3753
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003754 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3755 if (ret < 0)
3756 goto out_sleep;
3757
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003758out_sleep:
3759 wl1271_ps_elp_sleep(wl);
3760
Arik Nemtsov409622e2011-02-23 00:22:29 +02003761out_free_sta:
3762 if (ret < 0)
3763 wl1271_free_sta(wl, hlid);
3764
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003765out:
3766 mutex_unlock(&wl->mutex);
3767 return ret;
3768}
3769
3770static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3771 struct ieee80211_vif *vif,
3772 struct ieee80211_sta *sta)
3773{
3774 struct wl1271 *wl = hw->priv;
3775 struct wl1271_station *wl_sta;
3776 int ret = 0, id;
3777
3778 mutex_lock(&wl->mutex);
3779
3780 if (unlikely(wl->state == WL1271_STATE_OFF))
3781 goto out;
3782
3783 if (wl->bss_type != BSS_TYPE_AP_BSS)
3784 goto out;
3785
3786 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3787
3788 wl_sta = (struct wl1271_station *)sta->drv_priv;
3789 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3790 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3791 goto out;
3792
Ido Yariva6208652011-03-01 15:14:41 +02003793 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003794 if (ret < 0)
3795 goto out;
3796
Eliad Pellerc690ec82011-08-14 13:17:07 +03003797 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003798 if (ret < 0)
3799 goto out_sleep;
3800
Arik Nemtsov409622e2011-02-23 00:22:29 +02003801 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003802
3803out_sleep:
3804 wl1271_ps_elp_sleep(wl);
3805
3806out:
3807 mutex_unlock(&wl->mutex);
3808 return ret;
3809}
3810
Luciano Coelho4623ec72011-03-21 19:26:41 +02003811static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3812 struct ieee80211_vif *vif,
3813 enum ieee80211_ampdu_mlme_action action,
3814 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3815 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003816{
3817 struct wl1271 *wl = hw->priv;
3818 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003819 u8 hlid, *ba_bitmap;
3820
3821 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3822 tid);
3823
3824 /* sanity check - the fields in FW are only 8bits wide */
3825 if (WARN_ON(tid > 0xFF))
3826 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003827
3828 mutex_lock(&wl->mutex);
3829
3830 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3831 ret = -EAGAIN;
3832 goto out;
3833 }
3834
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003835 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3836 hlid = wl->sta_hlid;
3837 ba_bitmap = &wl->ba_rx_bitmap;
3838 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3839 struct wl1271_station *wl_sta;
3840
3841 wl_sta = (struct wl1271_station *)sta->drv_priv;
3842 hlid = wl_sta->hlid;
3843 ba_bitmap = &wl->links[hlid].ba_bitmap;
3844 } else {
3845 ret = -EINVAL;
3846 goto out;
3847 }
3848
Ido Yariva6208652011-03-01 15:14:41 +02003849 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003850 if (ret < 0)
3851 goto out;
3852
Shahar Levi70559a02011-05-22 16:10:22 +03003853 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3854 tid, action);
3855
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003856 switch (action) {
3857 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003858 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003859 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003860 break;
3861 }
3862
3863 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3864 ret = -EBUSY;
3865 wl1271_error("exceeded max RX BA sessions");
3866 break;
3867 }
3868
3869 if (*ba_bitmap & BIT(tid)) {
3870 ret = -EINVAL;
3871 wl1271_error("cannot enable RX BA session on active "
3872 "tid: %d", tid);
3873 break;
3874 }
3875
3876 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3877 hlid);
3878 if (!ret) {
3879 *ba_bitmap |= BIT(tid);
3880 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003881 }
3882 break;
3883
3884 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003885 if (!(*ba_bitmap & BIT(tid))) {
3886 ret = -EINVAL;
3887 wl1271_error("no active RX BA session on tid: %d",
3888 tid);
3889 break;
3890 }
3891
3892 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3893 hlid);
3894 if (!ret) {
3895 *ba_bitmap &= ~BIT(tid);
3896 wl->ba_rx_session_count--;
3897 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003898 break;
3899
3900 /*
3901 * The BA initiator session management in FW independently.
3902 * Falling break here on purpose for all TX APDU commands.
3903 */
3904 case IEEE80211_AMPDU_TX_START:
3905 case IEEE80211_AMPDU_TX_STOP:
3906 case IEEE80211_AMPDU_TX_OPERATIONAL:
3907 ret = -EINVAL;
3908 break;
3909
3910 default:
3911 wl1271_error("Incorrect ampdu action id=%x\n", action);
3912 ret = -EINVAL;
3913 }
3914
3915 wl1271_ps_elp_sleep(wl);
3916
3917out:
3918 mutex_unlock(&wl->mutex);
3919
3920 return ret;
3921}
3922
Arik Nemtsov33437892011-04-26 23:35:39 +03003923static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3924{
3925 struct wl1271 *wl = hw->priv;
3926 bool ret = false;
3927
3928 mutex_lock(&wl->mutex);
3929
3930 if (unlikely(wl->state == WL1271_STATE_OFF))
3931 goto out;
3932
3933 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003934 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003935
3936 /* the above is appropriate for STA mode for PS purposes */
3937 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3938
3939out:
3940 mutex_unlock(&wl->mutex);
3941
3942 return ret;
3943}
3944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003945/* can't be const, mac80211 writes to this */
3946static struct ieee80211_rate wl1271_rates[] = {
3947 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003948 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3949 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003950 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003951 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3952 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3954 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003955 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3956 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003957 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3958 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003959 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3960 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003961 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3962 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003963 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3964 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003965 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003966 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3967 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003968 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003969 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3970 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003972 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3973 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003974 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003975 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3976 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003977 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003978 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3979 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003980 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003981 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3982 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003983 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003984 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3985 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003986};
3987
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003988/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003989static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003990 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003991 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003992 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3993 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3994 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003995 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003996 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3997 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3998 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003999 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004000 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4001 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4002 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004003 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004004};
4005
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004006/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004007static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004008 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004009 7, /* CONF_HW_RXTX_RATE_MCS7 */
4010 6, /* CONF_HW_RXTX_RATE_MCS6 */
4011 5, /* CONF_HW_RXTX_RATE_MCS5 */
4012 4, /* CONF_HW_RXTX_RATE_MCS4 */
4013 3, /* CONF_HW_RXTX_RATE_MCS3 */
4014 2, /* CONF_HW_RXTX_RATE_MCS2 */
4015 1, /* CONF_HW_RXTX_RATE_MCS1 */
4016 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004017
4018 11, /* CONF_HW_RXTX_RATE_54 */
4019 10, /* CONF_HW_RXTX_RATE_48 */
4020 9, /* CONF_HW_RXTX_RATE_36 */
4021 8, /* CONF_HW_RXTX_RATE_24 */
4022
4023 /* TI-specific rate */
4024 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4025
4026 7, /* CONF_HW_RXTX_RATE_18 */
4027 6, /* CONF_HW_RXTX_RATE_12 */
4028 3, /* CONF_HW_RXTX_RATE_11 */
4029 5, /* CONF_HW_RXTX_RATE_9 */
4030 4, /* CONF_HW_RXTX_RATE_6 */
4031 2, /* CONF_HW_RXTX_RATE_5_5 */
4032 1, /* CONF_HW_RXTX_RATE_2 */
4033 0 /* CONF_HW_RXTX_RATE_1 */
4034};
4035
Shahar Levie8b03a22010-10-13 16:09:39 +02004036/* 11n STA capabilities */
4037#define HW_RX_HIGHEST_RATE 72
4038
Shahar Levi00d20102010-11-08 11:20:10 +00004039#ifdef CONFIG_WL12XX_HT
4040#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004041 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4042 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004043 .ht_supported = true, \
4044 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4045 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4046 .mcs = { \
4047 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4048 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4049 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4050 }, \
4051}
Shahar Levi18357852010-10-13 16:09:41 +02004052#else
Shahar Levi00d20102010-11-08 11:20:10 +00004053#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004054 .ht_supported = false, \
4055}
4056#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004058/* can't be const, mac80211 writes to this */
4059static struct ieee80211_supported_band wl1271_band_2ghz = {
4060 .channels = wl1271_channels,
4061 .n_channels = ARRAY_SIZE(wl1271_channels),
4062 .bitrates = wl1271_rates,
4063 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004064 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004065};
4066
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004067/* 5 GHz data rates for WL1273 */
4068static struct ieee80211_rate wl1271_rates_5ghz[] = {
4069 { .bitrate = 60,
4070 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4071 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4072 { .bitrate = 90,
4073 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4074 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4075 { .bitrate = 120,
4076 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4077 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4078 { .bitrate = 180,
4079 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4080 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4081 { .bitrate = 240,
4082 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4083 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4084 { .bitrate = 360,
4085 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4086 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4087 { .bitrate = 480,
4088 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4089 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4090 { .bitrate = 540,
4091 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4092 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4093};
4094
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004095/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004096static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004097 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4098 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4099 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4100 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4101 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4102 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4103 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4104 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4105 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4106 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4107 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4108 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4109 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4110 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4111 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4112 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4113 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4114 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4115 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4116 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4117 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4118 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4119 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4120 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4121 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4122 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4123 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4124 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4125 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4126 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4127 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4128 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4129 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4130 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004131};
4132
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004133/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004134static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004135 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004136 7, /* CONF_HW_RXTX_RATE_MCS7 */
4137 6, /* CONF_HW_RXTX_RATE_MCS6 */
4138 5, /* CONF_HW_RXTX_RATE_MCS5 */
4139 4, /* CONF_HW_RXTX_RATE_MCS4 */
4140 3, /* CONF_HW_RXTX_RATE_MCS3 */
4141 2, /* CONF_HW_RXTX_RATE_MCS2 */
4142 1, /* CONF_HW_RXTX_RATE_MCS1 */
4143 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004144
4145 7, /* CONF_HW_RXTX_RATE_54 */
4146 6, /* CONF_HW_RXTX_RATE_48 */
4147 5, /* CONF_HW_RXTX_RATE_36 */
4148 4, /* CONF_HW_RXTX_RATE_24 */
4149
4150 /* TI-specific rate */
4151 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4152
4153 3, /* CONF_HW_RXTX_RATE_18 */
4154 2, /* CONF_HW_RXTX_RATE_12 */
4155 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4156 1, /* CONF_HW_RXTX_RATE_9 */
4157 0, /* CONF_HW_RXTX_RATE_6 */
4158 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4159 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4160 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4161};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004162
4163static struct ieee80211_supported_band wl1271_band_5ghz = {
4164 .channels = wl1271_channels_5ghz,
4165 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4166 .bitrates = wl1271_rates_5ghz,
4167 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004168 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004169};
4170
Tobias Klausera0ea9492010-05-20 10:38:11 +02004171static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004172 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4173 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4174};
4175
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004176static const struct ieee80211_ops wl1271_ops = {
4177 .start = wl1271_op_start,
4178 .stop = wl1271_op_stop,
4179 .add_interface = wl1271_op_add_interface,
4180 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004181#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004182 .suspend = wl1271_op_suspend,
4183 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004184#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004185 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004186 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004187 .configure_filter = wl1271_op_configure_filter,
4188 .tx = wl1271_op_tx,
4189 .set_key = wl1271_op_set_key,
4190 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004191 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004192 .sched_scan_start = wl1271_op_sched_scan_start,
4193 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004194 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004195 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004196 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004197 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004198 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004199 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004200 .sta_add = wl1271_op_sta_add,
4201 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004202 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004203 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004204 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004205};
4206
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004207
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004208u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004209{
4210 u8 idx;
4211
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004212 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004213
4214 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4215 wl1271_error("Illegal RX rate from HW: %d", rate);
4216 return 0;
4217 }
4218
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004219 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004220 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4221 wl1271_error("Unsupported RX rate from HW: %d", rate);
4222 return 0;
4223 }
4224
4225 return idx;
4226}
4227
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004228static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4229 struct device_attribute *attr,
4230 char *buf)
4231{
4232 struct wl1271 *wl = dev_get_drvdata(dev);
4233 ssize_t len;
4234
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004235 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004236
4237 mutex_lock(&wl->mutex);
4238 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4239 wl->sg_enabled);
4240 mutex_unlock(&wl->mutex);
4241
4242 return len;
4243
4244}
4245
4246static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4247 struct device_attribute *attr,
4248 const char *buf, size_t count)
4249{
4250 struct wl1271 *wl = dev_get_drvdata(dev);
4251 unsigned long res;
4252 int ret;
4253
Luciano Coelho6277ed62011-04-01 17:49:54 +03004254 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004255 if (ret < 0) {
4256 wl1271_warning("incorrect value written to bt_coex_mode");
4257 return count;
4258 }
4259
4260 mutex_lock(&wl->mutex);
4261
4262 res = !!res;
4263
4264 if (res == wl->sg_enabled)
4265 goto out;
4266
4267 wl->sg_enabled = res;
4268
4269 if (wl->state == WL1271_STATE_OFF)
4270 goto out;
4271
Ido Yariva6208652011-03-01 15:14:41 +02004272 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004273 if (ret < 0)
4274 goto out;
4275
4276 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4277 wl1271_ps_elp_sleep(wl);
4278
4279 out:
4280 mutex_unlock(&wl->mutex);
4281 return count;
4282}
4283
4284static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4285 wl1271_sysfs_show_bt_coex_state,
4286 wl1271_sysfs_store_bt_coex_state);
4287
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004288static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4289 struct device_attribute *attr,
4290 char *buf)
4291{
4292 struct wl1271 *wl = dev_get_drvdata(dev);
4293 ssize_t len;
4294
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004295 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004296
4297 mutex_lock(&wl->mutex);
4298 if (wl->hw_pg_ver >= 0)
4299 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4300 else
4301 len = snprintf(buf, len, "n/a\n");
4302 mutex_unlock(&wl->mutex);
4303
4304 return len;
4305}
4306
Gery Kahn6f07b722011-07-18 14:21:49 +03004307static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004308 wl1271_sysfs_show_hw_pg_ver, NULL);
4309
Ido Yariv95dac04f2011-06-06 14:57:06 +03004310static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4311 struct bin_attribute *bin_attr,
4312 char *buffer, loff_t pos, size_t count)
4313{
4314 struct device *dev = container_of(kobj, struct device, kobj);
4315 struct wl1271 *wl = dev_get_drvdata(dev);
4316 ssize_t len;
4317 int ret;
4318
4319 ret = mutex_lock_interruptible(&wl->mutex);
4320 if (ret < 0)
4321 return -ERESTARTSYS;
4322
4323 /* Let only one thread read the log at a time, blocking others */
4324 while (wl->fwlog_size == 0) {
4325 DEFINE_WAIT(wait);
4326
4327 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4328 &wait,
4329 TASK_INTERRUPTIBLE);
4330
4331 if (wl->fwlog_size != 0) {
4332 finish_wait(&wl->fwlog_waitq, &wait);
4333 break;
4334 }
4335
4336 mutex_unlock(&wl->mutex);
4337
4338 schedule();
4339 finish_wait(&wl->fwlog_waitq, &wait);
4340
4341 if (signal_pending(current))
4342 return -ERESTARTSYS;
4343
4344 ret = mutex_lock_interruptible(&wl->mutex);
4345 if (ret < 0)
4346 return -ERESTARTSYS;
4347 }
4348
4349 /* Check if the fwlog is still valid */
4350 if (wl->fwlog_size < 0) {
4351 mutex_unlock(&wl->mutex);
4352 return 0;
4353 }
4354
4355 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4356 len = min(count, (size_t)wl->fwlog_size);
4357 wl->fwlog_size -= len;
4358 memcpy(buffer, wl->fwlog, len);
4359
4360 /* Make room for new messages */
4361 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4362
4363 mutex_unlock(&wl->mutex);
4364
4365 return len;
4366}
4367
4368static struct bin_attribute fwlog_attr = {
4369 .attr = {.name = "fwlog", .mode = S_IRUSR},
4370 .read = wl1271_sysfs_read_fwlog,
4371};
4372
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004373int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004374{
4375 int ret;
4376
4377 if (wl->mac80211_registered)
4378 return 0;
4379
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004380 ret = wl1271_fetch_nvs(wl);
4381 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004382 /* NOTE: The wl->nvs->nvs element must be first, in
4383 * order to simplify the casting, we assume it is at
4384 * the beginning of the wl->nvs structure.
4385 */
4386 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004387
4388 wl->mac_addr[0] = nvs_ptr[11];
4389 wl->mac_addr[1] = nvs_ptr[10];
4390 wl->mac_addr[2] = nvs_ptr[6];
4391 wl->mac_addr[3] = nvs_ptr[5];
4392 wl->mac_addr[4] = nvs_ptr[4];
4393 wl->mac_addr[5] = nvs_ptr[3];
4394 }
4395
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004396 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4397
4398 ret = ieee80211_register_hw(wl->hw);
4399 if (ret < 0) {
4400 wl1271_error("unable to register mac80211 hw: %d", ret);
4401 return ret;
4402 }
4403
4404 wl->mac80211_registered = true;
4405
Eliad Pellerd60080a2010-11-24 12:53:16 +02004406 wl1271_debugfs_init(wl);
4407
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004408 register_netdevice_notifier(&wl1271_dev_notifier);
4409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410 wl1271_notice("loaded");
4411
4412 return 0;
4413}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004414EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004416void wl1271_unregister_hw(struct wl1271 *wl)
4417{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004418 if (wl->state == WL1271_STATE_PLT)
4419 __wl1271_plt_stop(wl);
4420
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004421 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004422 ieee80211_unregister_hw(wl->hw);
4423 wl->mac80211_registered = false;
4424
4425}
4426EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4427
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004428int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004430 static const u32 cipher_suites[] = {
4431 WLAN_CIPHER_SUITE_WEP40,
4432 WLAN_CIPHER_SUITE_WEP104,
4433 WLAN_CIPHER_SUITE_TKIP,
4434 WLAN_CIPHER_SUITE_CCMP,
4435 WL1271_CIPHER_SUITE_GEM,
4436 };
4437
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004438 /* The tx descriptor buffer and the TKIP space. */
4439 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4440 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441
4442 /* unit us */
4443 /* FIXME: find a proper value */
4444 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004445 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446
4447 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004448 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004449 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004450 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004451 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004452 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004453 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004454 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004455 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004456 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004458 wl->hw->wiphy->cipher_suites = cipher_suites;
4459 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4460
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004461 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004462 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004463 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004464 /*
4465 * Maximum length of elements in scanning probe request templates
4466 * should be the maximum length possible for a template, without
4467 * the IEEE80211 header of the template
4468 */
Eliad Peller154037d2011-08-14 13:17:12 +03004469 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004470 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004471
Luciano Coelho4a31c112011-03-21 23:16:14 +02004472 /* make sure all our channels fit in the scanned_ch bitmask */
4473 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4474 ARRAY_SIZE(wl1271_channels_5ghz) >
4475 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004476 /*
4477 * We keep local copies of the band structs because we need to
4478 * modify them on a per-device basis.
4479 */
4480 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4481 sizeof(wl1271_band_2ghz));
4482 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4483 sizeof(wl1271_band_5ghz));
4484
4485 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4486 &wl->bands[IEEE80211_BAND_2GHZ];
4487 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4488 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004489
Kalle Valo12bd8942010-03-18 12:26:33 +02004490 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004491 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004492
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004493 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4494
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004495 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004496
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004497 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4498
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004499 wl->hw->max_rx_aggregation_subframes = 8;
4500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501 return 0;
4502}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004503EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004504
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004505#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004506
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004507struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004508{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004509 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004510 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004511 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004512 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004513 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004514
4515 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4516 if (!hw) {
4517 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004518 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004519 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004520 }
4521
Julia Lawall929ebd32010-05-15 23:16:39 +02004522 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004523 if (!plat_dev) {
4524 wl1271_error("could not allocate platform_device");
4525 ret = -ENOMEM;
4526 goto err_plat_alloc;
4527 }
4528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004529 wl = hw->priv;
4530 memset(wl, 0, sizeof(*wl));
4531
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004532 INIT_LIST_HEAD(&wl->list);
4533
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004534 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004535 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004536
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004537 for (i = 0; i < NUM_TX_QUEUES; i++)
4538 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004540 for (i = 0; i < NUM_TX_QUEUES; i++)
4541 for (j = 0; j < AP_MAX_LINKS; j++)
4542 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4543
Ido Yariva6208652011-03-01 15:14:41 +02004544 skb_queue_head_init(&wl->deferred_rx_queue);
4545 skb_queue_head_init(&wl->deferred_tx_queue);
4546
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004547 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004548 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004549 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004550 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4551 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4552 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004553 INIT_WORK(&wl->rx_streaming_enable_work,
4554 wl1271_rx_streaming_enable_work);
4555 INIT_WORK(&wl->rx_streaming_disable_work,
4556 wl1271_rx_streaming_disable_work);
4557
Eliad Peller92ef8962011-06-07 12:50:46 +03004558 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4559 if (!wl->freezable_wq) {
4560 ret = -ENOMEM;
4561 goto err_hw;
4562 }
4563
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004564 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004565 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004566 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004567 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004568 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004569 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004570 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004571 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004572 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004573 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004574 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004575 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004576 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004577 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004578 wl->bss_type = MAX_BSS_TYPE;
4579 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004580 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004581 wl->ap_ps_map = 0;
4582 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004583 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004584 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004585 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004586 wl->tx_security_seq = 0;
4587 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004588 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004589 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004590 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004591 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4592 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004593 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004594 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4595 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004596 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4597 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004598 wl->fwlog_size = 0;
4599 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004600
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004601 /* The system link is always allocated */
4602 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4603
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004604 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004605 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004606 wl->tx_frames[i] = NULL;
4607
4608 spin_lock_init(&wl->wl_lock);
4609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004610 wl->state = WL1271_STATE_OFF;
4611 mutex_init(&wl->mutex);
4612
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004613 /* Apply default driver configuration. */
4614 wl1271_conf_init(wl);
4615
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004616 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4617 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4618 if (!wl->aggr_buf) {
4619 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004620 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004621 }
4622
Ido Yariv990f5de2011-03-31 10:06:59 +02004623 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4624 if (!wl->dummy_packet) {
4625 ret = -ENOMEM;
4626 goto err_aggr;
4627 }
4628
Ido Yariv95dac04f2011-06-06 14:57:06 +03004629 /* Allocate one page for the FW log */
4630 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4631 if (!wl->fwlog) {
4632 ret = -ENOMEM;
4633 goto err_dummy_packet;
4634 }
4635
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004636 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004637 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004638 if (ret) {
4639 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004640 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004641 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004642 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004643
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004644 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004645 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004646 if (ret < 0) {
4647 wl1271_error("failed to create sysfs file bt_coex_state");
4648 goto err_platform;
4649 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004650
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004651 /* Create sysfs file to get HW PG version */
4652 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4653 if (ret < 0) {
4654 wl1271_error("failed to create sysfs file hw_pg_ver");
4655 goto err_bt_coex_state;
4656 }
4657
Ido Yariv95dac04f2011-06-06 14:57:06 +03004658 /* Create sysfs file for the FW log */
4659 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4660 if (ret < 0) {
4661 wl1271_error("failed to create sysfs file fwlog");
4662 goto err_hw_pg_ver;
4663 }
4664
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004665 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004666
Ido Yariv95dac04f2011-06-06 14:57:06 +03004667err_hw_pg_ver:
4668 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4669
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004670err_bt_coex_state:
4671 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4672
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004673err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004674 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004675
Ido Yariv95dac04f2011-06-06 14:57:06 +03004676err_fwlog:
4677 free_page((unsigned long)wl->fwlog);
4678
Ido Yariv990f5de2011-03-31 10:06:59 +02004679err_dummy_packet:
4680 dev_kfree_skb(wl->dummy_packet);
4681
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004682err_aggr:
4683 free_pages((unsigned long)wl->aggr_buf, order);
4684
Eliad Peller92ef8962011-06-07 12:50:46 +03004685err_wq:
4686 destroy_workqueue(wl->freezable_wq);
4687
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004688err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004689 wl1271_debugfs_exit(wl);
4690 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004691
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004692err_plat_alloc:
4693 ieee80211_free_hw(hw);
4694
4695err_hw_alloc:
4696
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004697 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004698}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004699EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004700
4701int wl1271_free_hw(struct wl1271 *wl)
4702{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004703 /* Unblock any fwlog readers */
4704 mutex_lock(&wl->mutex);
4705 wl->fwlog_size = -1;
4706 wake_up_interruptible_all(&wl->fwlog_waitq);
4707 mutex_unlock(&wl->mutex);
4708
4709 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004710
4711 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4712
4713 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004714 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004715 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004716 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004717 free_pages((unsigned long)wl->aggr_buf,
4718 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004719 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004720
4721 wl1271_debugfs_exit(wl);
4722
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004723 vfree(wl->fw);
4724 wl->fw = NULL;
4725 kfree(wl->nvs);
4726 wl->nvs = NULL;
4727
4728 kfree(wl->fw_status);
4729 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004730 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004731
4732 ieee80211_free_hw(wl->hw);
4733
4734 return 0;
4735}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004736EXPORT_SYMBOL_GPL(wl1271_free_hw);
4737
Guy Eilam491bbd62011-01-12 10:33:29 +01004738u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004739EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004740module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004741MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4742
Ido Yariv95dac04f2011-06-06 14:57:06 +03004743module_param_named(fwlog, fwlog_param, charp, 0);
4744MODULE_PARM_DESC(keymap,
4745 "FW logger options: continuous, ondemand, dbgpins or disable");
4746
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004747MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004748MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004749MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");