blob: c72f7497db095e8e9b1b133e523f28114ed17dfa [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>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000039#include "reg.h"
40#include "io.h"
41#include "event.h"
42#include "tx.h"
43#include "rx.h"
44#include "ps.h"
45#include "init.h"
46#include "debugfs.h"
47#include "cmd.h"
48#include "boot.h"
49#include "testmode.h"
50#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030051
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020052#define WL1271_BOOT_RETRIES 3
53
Juuso Oikarinen8a080482009-10-13 12:47:44 +030054static struct conf_drv_settings default_conf = {
55 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030056 .params = {
57 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
58 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
59 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
62 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
63 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
65 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
79 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
80 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
83 /* active scan params */
84 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
87 /* passive scan params */
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
91 /* passive scan in dual antenna params */
92 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
95 /* general params */
96 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
97 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
98 [CONF_SG_BEACON_MISS_PERCENT] = 60,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_RXT] = 1200,
101 [CONF_SG_TXT] = 1000,
102 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
103 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
104 [CONF_SG_HV3_MAX_SERVED] = 6,
105 [CONF_SG_PS_POLL_TIMEOUT] = 10,
106 [CONF_SG_UPSD_TIMEOUT] = 10,
107 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
108 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
109 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
110 /* AP params */
111 [CONF_AP_BEACON_MISS_TX] = 3,
112 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
113 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
114 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
115 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
116 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300117 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200118 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300119 },
120 .rx = {
121 .rx_msdu_life_time = 512000,
122 .packet_detection_threshold = 0,
123 .ps_poll_timeout = 15,
124 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300125 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200126 .rx_cca_threshold = 0,
127 .irq_blk_threshold = 0xFFFF,
128 .irq_pkt_threshold = 0,
129 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300130 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
131 },
132 .tx = {
133 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200134 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300135 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300136 .short_retry_limit = 10,
137 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200138 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300139 },
140 .ac_conf_count = 4,
141 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200142 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300143 .ac = CONF_TX_AC_BE,
144 .cw_min = 15,
145 .cw_max = 63,
146 .aifsn = 3,
147 .tx_op_limit = 0,
148 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200149 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300150 .ac = CONF_TX_AC_BK,
151 .cw_min = 15,
152 .cw_max = 63,
153 .aifsn = 7,
154 .tx_op_limit = 0,
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .ac = CONF_TX_AC_VI,
158 .cw_min = 15,
159 .cw_max = 63,
160 .aifsn = CONF_TX_AIFS_PIFS,
161 .tx_op_limit = 3008,
162 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200163 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300164 .ac = CONF_TX_AC_VO,
165 .cw_min = 15,
166 .cw_max = 63,
167 .aifsn = CONF_TX_AIFS_PIFS,
168 .tx_op_limit = 1504,
169 },
170 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300171 .max_tx_retries = 100,
172 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200173 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300174 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200175 [CONF_TX_AC_BE] = {
176 .queue_id = CONF_TX_AC_BE,
177 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .tsid = CONF_TX_AC_BE,
179 .ps_scheme = CONF_PS_SCHEME_LEGACY,
180 .ack_policy = CONF_ACK_POLICY_LEGACY,
181 .apsd_conf = {0, 0},
182 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BK] = {
184 .queue_id = CONF_TX_AC_BK,
185 .channel_type = CONF_CHANNEL_TYPE_EDCF,
186 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300187 .ps_scheme = CONF_PS_SCHEME_LEGACY,
188 .ack_policy = CONF_ACK_POLICY_LEGACY,
189 .apsd_conf = {0, 0},
190 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200191 [CONF_TX_AC_VI] = {
192 .queue_id = CONF_TX_AC_VI,
193 .channel_type = CONF_CHANNEL_TYPE_EDCF,
194 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300195 .ps_scheme = CONF_PS_SCHEME_LEGACY,
196 .ack_policy = CONF_ACK_POLICY_LEGACY,
197 .apsd_conf = {0, 0},
198 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200199 [CONF_TX_AC_VO] = {
200 .queue_id = CONF_TX_AC_VO,
201 .channel_type = CONF_CHANNEL_TYPE_EDCF,
202 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300203 .ps_scheme = CONF_PS_SCHEME_LEGACY,
204 .ack_policy = CONF_ACK_POLICY_LEGACY,
205 .apsd_conf = {0, 0},
206 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300207 },
208 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200209 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300210 .tx_compl_threshold = 4,
211 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
212 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200213 .tmpl_short_retry_limit = 10,
214 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300215 },
216 .conn = {
217 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300218 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300220 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300221 .bcn_filt_ie = {
222 [0] = {
223 .ie = WLAN_EID_CHANNEL_SWITCH,
224 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300225 },
226 [1] = {
227 .ie = WLAN_EID_HT_INFORMATION,
228 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
229 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300236 .ps_poll_threshold = 10,
237 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300238 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200239 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300240 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300241 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200242 .psm_entry_nullfunc_retries = 3,
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 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300270 .min_dwell_time_active = 30,
271 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300272 .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 },
Eliad Peller94877752011-08-28 15:11:56 +0300362 .hangover = {
363 .recover_time = 0,
364 .hangover_period = 20,
365 .dynamic_mode = 1,
366 .early_termination_mode = 1,
367 .max_period = 20,
368 .min_period = 1,
369 .increase_delta = 1,
370 .decrease_delta = 2,
371 .quiet_time = 4,
372 .increase_time = 1,
373 .window_size = 16,
374 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300375};
376
Ido Yariv95dac04f2011-06-06 14:57:06 +0300377static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300378static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300379
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300380static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200381 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300382 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200383static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200384static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200385
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 Pellerba8447f2011-10-10 10:13:00 +0200389static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
390 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300391{
392 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200393
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300394 if (operstate != IF_OPER_UP)
395 return 0;
396
Eliad Peller8181aec2011-10-10 10:13:04 +0200397 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300398 return 0;
399
Eliad Peller154da672011-10-05 11:55:53 +0200400 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300401 if (ret < 0)
402 return ret;
403
Eliad Peller0603d892011-10-05 11:55:51 +0200404 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300405
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300406 wl1271_info("Association completed.");
407 return 0;
408}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300409static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
410 void *arg)
411{
412 struct net_device *dev = arg;
413 struct wireless_dev *wdev;
414 struct wiphy *wiphy;
415 struct ieee80211_hw *hw;
416 struct wl1271 *wl;
417 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200418 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300419 int ret = 0;
420
421 /* Check that this notification is for us. */
422 if (what != NETDEV_CHANGE)
423 return NOTIFY_DONE;
424
425 wdev = dev->ieee80211_ptr;
426 if (wdev == NULL)
427 return NOTIFY_DONE;
428
429 wiphy = wdev->wiphy;
430 if (wiphy == NULL)
431 return NOTIFY_DONE;
432
433 hw = wiphy_priv(wiphy);
434 if (hw == NULL)
435 return NOTIFY_DONE;
436
437 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200438 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300439 list_for_each_entry(wl, &wl_list, list) {
440 if (wl == wl_temp)
441 break;
442 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200443 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300444 if (wl != wl_temp)
445 return NOTIFY_DONE;
446
447 mutex_lock(&wl->mutex);
448
449 if (wl->state == WL1271_STATE_OFF)
450 goto out;
451
Eliad Pellerba8447f2011-10-10 10:13:00 +0200452 wl12xx_for_each_wlvif_sta(wl, wlvif) {
453 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
454 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300455
Eliad Pellerba8447f2011-10-10 10:13:00 +0200456 ret = wl1271_ps_elp_wakeup(wl);
457 if (ret < 0)
458 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300459
Eliad Pellerba8447f2011-10-10 10:13:00 +0200460 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300461
Eliad Pellerba8447f2011-10-10 10:13:00 +0200462 wl1271_ps_elp_sleep(wl);
463 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300464out:
465 mutex_unlock(&wl->mutex);
466
467 return NOTIFY_OK;
468}
469
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100470static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200471 struct regulatory_request *request)
472{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100473 struct ieee80211_supported_band *band;
474 struct ieee80211_channel *ch;
475 int i;
476
477 band = wiphy->bands[IEEE80211_BAND_5GHZ];
478 for (i = 0; i < band->n_channels; i++) {
479 ch = &band->channels[i];
480 if (ch->flags & IEEE80211_CHAN_DISABLED)
481 continue;
482
483 if (ch->flags & IEEE80211_CHAN_RADAR)
484 ch->flags |= IEEE80211_CHAN_NO_IBSS |
485 IEEE80211_CHAN_PASSIVE_SCAN;
486
487 }
488
489 return 0;
490}
491
Eliad Peller9eb599e2011-10-10 10:12:59 +0200492static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
493 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300494{
495 int ret = 0;
496
497 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200498 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300499 if (ret < 0)
500 goto out;
501
502 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200503 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300504 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200505 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300506out:
507 return ret;
508}
509
510/*
511 * this function is being called when the rx_streaming interval
512 * has beed changed or rx_streaming should be disabled
513 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200514int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515{
516 int ret = 0;
517 int period = wl->conf.rx_streaming.interval;
518
519 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200520 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300521 goto out;
522
523 /* reconfigure/disable according to new streaming_period */
524 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200525 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526 (wl->conf.rx_streaming.always ||
527 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200528 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300529 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200530 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300531 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200532 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300533 }
534out:
535 return ret;
536}
537
538static void wl1271_rx_streaming_enable_work(struct work_struct *work)
539{
540 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
542 rx_streaming_enable_work);
543 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544
545 mutex_lock(&wl->mutex);
546
Eliad Peller0744bdb2011-10-10 10:13:05 +0200547 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200548 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300549 (!wl->conf.rx_streaming.always &&
550 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
551 goto out;
552
553 if (!wl->conf.rx_streaming.interval)
554 goto out;
555
556 ret = wl1271_ps_elp_wakeup(wl);
557 if (ret < 0)
558 goto out;
559
Eliad Peller9eb599e2011-10-10 10:12:59 +0200560 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300561 if (ret < 0)
562 goto out_sleep;
563
564 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200565 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300566 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
567
568out_sleep:
569 wl1271_ps_elp_sleep(wl);
570out:
571 mutex_unlock(&wl->mutex);
572}
573
574static void wl1271_rx_streaming_disable_work(struct work_struct *work)
575{
576 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200577 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
578 rx_streaming_disable_work);
579 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300580
581 mutex_lock(&wl->mutex);
582
Eliad Peller0744bdb2011-10-10 10:13:05 +0200583 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300584 goto out;
585
586 ret = wl1271_ps_elp_wakeup(wl);
587 if (ret < 0)
588 goto out;
589
Eliad Peller9eb599e2011-10-10 10:12:59 +0200590 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591 if (ret)
592 goto out_sleep;
593
594out_sleep:
595 wl1271_ps_elp_sleep(wl);
596out:
597 mutex_unlock(&wl->mutex);
598}
599
600static void wl1271_rx_streaming_timer(unsigned long data)
601{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200602 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
603 struct wl1271 *wl = wlvif->wl;
604 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300605}
606
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300607static void wl1271_conf_init(struct wl1271 *wl)
608{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300609
610 /*
611 * This function applies the default configuration to the driver. This
612 * function is invoked upon driver load (spi probe.)
613 *
614 * The configuration is stored in a run-time structure in order to
615 * facilitate for run-time adjustment of any of the parameters. Making
616 * changes to the configuration structure will apply the new values on
617 * the next interface up (wl1271_op_start.)
618 */
619
620 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300621 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300622
Ido Yariv95dac04f2011-06-06 14:57:06 +0300623 /* Adjust settings according to optional module parameters */
624 if (fwlog_param) {
625 if (!strcmp(fwlog_param, "continuous")) {
626 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
627 } else if (!strcmp(fwlog_param, "ondemand")) {
628 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
629 } else if (!strcmp(fwlog_param, "dbgpins")) {
630 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
631 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
632 } else if (!strcmp(fwlog_param, "disable")) {
633 wl->conf.fwlog.mem_blocks = 0;
634 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
635 } else {
636 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
637 }
638 }
639}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300640
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641static int wl1271_plt_init(struct wl1271 *wl)
642{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200643 struct conf_tx_ac_category *conf_ac;
644 struct conf_tx_tid *conf_tid;
645 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646
Shahar Levi49d750ca2011-03-06 16:32:09 +0200647 if (wl->chip.id == CHIP_ID_1283_PG20)
648 ret = wl128x_cmd_general_parms(wl);
649 else
650 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200651 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200652 return ret;
653
Shahar Levi49d750ca2011-03-06 16:32:09 +0200654 if (wl->chip.id == CHIP_ID_1283_PG20)
655 ret = wl128x_cmd_radio_parms(wl);
656 else
657 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200658 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200659 return ret;
660
Shahar Levi49d750ca2011-03-06 16:32:09 +0200661 if (wl->chip.id != CHIP_ID_1283_PG20) {
662 ret = wl1271_cmd_ext_radio_parms(wl);
663 if (ret < 0)
664 return ret;
665 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200666 if (ret < 0)
667 return ret;
668
Shahar Levi48a61472011-03-06 16:32:08 +0200669 /* Chip-specific initializations */
670 ret = wl1271_chip_specific_init(wl);
671 if (ret < 0)
672 return ret;
673
Eliad Peller92c77c72011-10-05 11:55:40 +0200674 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200675 if (ret < 0)
676 return ret;
677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 ret = wl1271_acx_init_mem_config(wl);
679 if (ret < 0)
680 return ret;
681
Luciano Coelho12419cc2010-02-18 13:25:44 +0200682 /* PHY layer config */
683 ret = wl1271_init_phy_config(wl);
684 if (ret < 0)
685 goto out_free_memmap;
686
687 ret = wl1271_acx_dco_itrim_params(wl);
688 if (ret < 0)
689 goto out_free_memmap;
690
691 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200692 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* Bluetooth WLAN coexistence */
697 ret = wl1271_init_pta(wl);
698 if (ret < 0)
699 goto out_free_memmap;
700
Shahar Leviff868432011-04-11 15:41:46 +0300701 /* FM WLAN coexistence */
702 ret = wl1271_acx_fm_coex(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
Luciano Coelho12419cc2010-02-18 13:25:44 +0200706 /* Energy detection */
707 ret = wl1271_init_energy_detection(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Eliad Peller7f0979882011-08-14 13:17:06 +0300711 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600712 if (ret < 0)
713 goto out_free_memmap;
714
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100716 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200717 if (ret < 0)
718 goto out_free_memmap;
719
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200720 /* Default TID/AC configuration */
721 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200723 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200724 /* TODO: fix */
725 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200726 conf_ac->cw_max, conf_ac->aifsn,
727 conf_ac->tx_op_limit);
728 if (ret < 0)
729 goto out_free_memmap;
730
Luciano Coelho12419cc2010-02-18 13:25:44 +0200731 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200732 /* TODO: fix */
733 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200734 conf_tid->channel_type,
735 conf_tid->tsid,
736 conf_tid->ps_scheme,
737 conf_tid->ack_policy,
738 conf_tid->apsd_conf[0],
739 conf_tid->apsd_conf[1]);
740 if (ret < 0)
741 goto out_free_memmap;
742 }
743
Luciano Coelho12419cc2010-02-18 13:25:44 +0200744 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200745 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 goto out_free_memmap;
748
749 /* Configure for CAM power saving (ie. always active) */
750 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
751 if (ret < 0)
752 goto out_free_memmap;
753
754 /* configure PM */
755 ret = wl1271_acx_pm_config(wl);
756 if (ret < 0)
757 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300758
759 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200760
761 out_free_memmap:
762 kfree(wl->target_mem_map);
763 wl->target_mem_map = NULL;
764
765 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766}
767
Eliad Peller6e8cd332011-10-10 10:13:13 +0200768static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
769 struct wl12xx_vif *wlvif,
770 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200771{
Arik Nemtsovda032092011-08-25 12:43:15 +0300772 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200773
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300775 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200776
777 /*
778 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300779 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200780 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300781 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200782 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200783
Arik Nemtsovda032092011-08-25 12:43:15 +0300784 /*
785 * Start high-level PS if the STA is asleep with enough blocks in FW.
786 * Make an exception if this is the only connected station. In this
787 * case FW-memory congestion is not a problem.
788 */
789 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200790 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200791}
792
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300793static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200794 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300795 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200796{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200797 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200798 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300799 u8 hlid, cnt;
800
801 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200802
803 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
804 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
805 wl1271_debug(DEBUG_PSM,
806 "link ps prev 0x%x cur 0x%x changed 0x%x",
807 wl->ap_fw_ps_map, cur_fw_ps_map,
808 wl->ap_fw_ps_map ^ cur_fw_ps_map);
809
810 wl->ap_fw_ps_map = cur_fw_ps_map;
811 }
812
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200813 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
814 lnk = &wl->links[hlid];
815 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200816
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200817 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
818 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200819
Eliad Peller6e8cd332011-10-10 10:13:13 +0200820 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
821 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200822 }
823}
824
Eliad Peller4d56ad92011-08-14 13:17:05 +0300825static void wl12xx_fw_status(struct wl1271 *wl,
826 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200828 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200829 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200830 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300831 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300832 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833
Eliad Peller4d56ad92011-08-14 13:17:05 +0300834 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200835
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
837 "drv_rx_counter = %d, tx_results_counter = %d)",
838 status->intr,
839 status->fw_rx_counter,
840 status->drv_rx_counter,
841 status->tx_results_counter);
842
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300843 for (i = 0; i < NUM_TX_QUEUES; i++) {
844 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300845 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300846 (status->tx_released_pkts[i] -
847 wl->tx_pkts_freed[i]) & 0xff;
848
849 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
850 }
851
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300852 /* prevent wrap-around in total blocks counter */
853 if (likely(wl->tx_blocks_freed <=
854 le32_to_cpu(status->total_released_blks)))
855 freed_blocks = le32_to_cpu(status->total_released_blks) -
856 wl->tx_blocks_freed;
857 else
858 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
859 le32_to_cpu(status->total_released_blks);
860
Eliad Peller4d56ad92011-08-14 13:17:05 +0300861 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200862
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300863 wl->tx_allocated_blocks -= freed_blocks;
864
Eliad Peller4d56ad92011-08-14 13:17:05 +0300865 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200866
Eliad Peller4d56ad92011-08-14 13:17:05 +0300867 /*
868 * The FW might change the total number of TX memblocks before
869 * we get a notification about blocks being released. Thus, the
870 * available blocks calculation might yield a temporary result
871 * which is lower than the actual available blocks. Keeping in
872 * mind that only blocks that were allocated can be moved from
873 * TX to RX, tx_blocks_available should never decrease here.
874 */
875 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
876 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877
Ido Yariva5225502010-10-12 14:49:10 +0200878 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200879 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200880 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
Eliad Peller4d56ad92011-08-14 13:17:05 +0300882 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200883 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200884 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200885 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200888 getnstimeofday(&ts);
889 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
890 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891}
892
Ido Yariva6208652011-03-01 15:14:41 +0200893static void wl1271_flush_deferred_work(struct wl1271 *wl)
894{
895 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200896
Ido Yariva6208652011-03-01 15:14:41 +0200897 /* Pass all received frames to the network stack */
898 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
899 ieee80211_rx_ni(wl->hw, skb);
900
901 /* Return sent skbs to the network stack */
902 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300903 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200904}
905
906static void wl1271_netstack_work(struct work_struct *work)
907{
908 struct wl1271 *wl =
909 container_of(work, struct wl1271, netstack_work);
910
911 do {
912 wl1271_flush_deferred_work(wl);
913 } while (skb_queue_len(&wl->deferred_rx_queue));
914}
915
916#define WL1271_IRQ_MAX_LOOPS 256
917
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300918static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300921 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200922 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200923 struct wl1271 *wl = (struct wl1271 *)cookie;
924 bool done = false;
925 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200926 unsigned long flags;
927
928 /* TX might be handled here, avoid redundant work */
929 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
930 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931
Ido Yariv341b7cd2011-03-31 10:07:01 +0200932 /*
933 * In case edge triggered interrupt must be used, we cannot iterate
934 * more than once without introducing race conditions with the hardirq.
935 */
936 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
937 loopcount = 1;
938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 mutex_lock(&wl->mutex);
940
941 wl1271_debug(DEBUG_IRQ, "IRQ work");
942
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200943 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 goto out;
945
Ido Yariva6208652011-03-01 15:14:41 +0200946 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 if (ret < 0)
948 goto out;
949
Ido Yariva6208652011-03-01 15:14:41 +0200950 while (!done && loopcount--) {
951 /*
952 * In order to avoid a race with the hardirq, clear the flag
953 * before acknowledging the chip. Since the mutex is held,
954 * wl1271_ps_elp_wakeup cannot be called concurrently.
955 */
956 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
957 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200958
Eliad Peller4d56ad92011-08-14 13:17:05 +0300959 wl12xx_fw_status(wl, wl->fw_status);
960 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200961 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200962 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200963 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200964 continue;
965 }
966
Eliad Pellerccc83b02010-10-27 14:09:57 +0200967 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
968 wl1271_error("watchdog interrupt received! "
969 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300970 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200971
972 /* restarting the chip. ignore any other interrupt. */
973 goto out;
974 }
975
Ido Yariva6208652011-03-01 15:14:41 +0200976 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200977 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
978
Eliad Peller4d56ad92011-08-14 13:17:05 +0300979 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200980
Ido Yariva5225502010-10-12 14:49:10 +0200981 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200982 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200983 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300984 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200985 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200986 /*
987 * In order to avoid starvation of the TX path,
988 * call the work function directly.
989 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200990 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200991 } else {
992 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200993 }
994
Ido Yariv8aad2462011-03-01 15:14:38 +0200995 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300996 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200997 (wl->tx_results_count & 0xff))
998 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200999
1000 /* Make sure the deferred queues don't get too long */
1001 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1002 skb_queue_len(&wl->deferred_rx_queue);
1003 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1004 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001005 }
1006
1007 if (intr & WL1271_ACX_INTR_EVENT_A) {
1008 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1009 wl1271_event_handle(wl, 0);
1010 }
1011
1012 if (intr & WL1271_ACX_INTR_EVENT_B) {
1013 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1014 wl1271_event_handle(wl, 1);
1015 }
1016
1017 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1018 wl1271_debug(DEBUG_IRQ,
1019 "WL1271_ACX_INTR_INIT_COMPLETE");
1020
1021 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1022 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 }
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 wl1271_ps_elp_sleep(wl);
1026
1027out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001028 spin_lock_irqsave(&wl->wl_lock, flags);
1029 /* In case TX was not handled here, queue TX work */
1030 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1031 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001032 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001033 ieee80211_queue_work(wl->hw, &wl->tx_work);
1034 spin_unlock_irqrestore(&wl->wl_lock, flags);
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001037
1038 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039}
1040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041static int wl1271_fetch_firmware(struct wl1271 *wl)
1042{
1043 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001044 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 int ret;
1046
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001047 if (wl->chip.id == CHIP_ID_1283_PG20)
1048 fw_name = WL128X_FW_NAME;
1049 else
1050 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001051
1052 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1053
Felipe Balbia390e852011-10-06 10:07:44 +03001054 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 if (ret < 0) {
1057 wl1271_error("could not get firmware: %d", ret);
1058 return ret;
1059 }
1060
1061 if (fw->size % 4) {
1062 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1063 fw->size);
1064 ret = -EILSEQ;
1065 goto out;
1066 }
1067
Arik Nemtsov166d5042010-10-16 21:44:57 +02001068 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001070 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071
1072 if (!wl->fw) {
1073 wl1271_error("could not allocate memory for the firmware");
1074 ret = -ENOMEM;
1075 goto out;
1076 }
1077
1078 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 ret = 0;
1080
1081out:
1082 release_firmware(fw);
1083
1084 return ret;
1085}
1086
1087static int wl1271_fetch_nvs(struct wl1271 *wl)
1088{
1089 const struct firmware *fw;
1090 int ret;
1091
Felipe Balbia390e852011-10-06 10:07:44 +03001092 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093
1094 if (ret < 0) {
1095 wl1271_error("could not get nvs file: %d", ret);
1096 return ret;
1097 }
1098
Shahar Levibc765bf2011-03-06 16:32:10 +02001099 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100
1101 if (!wl->nvs) {
1102 wl1271_error("could not allocate memory for the nvs file");
1103 ret = -ENOMEM;
1104 goto out;
1105 }
1106
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001107 wl->nvs_len = fw->size;
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109out:
1110 release_firmware(fw);
1111
1112 return ret;
1113}
1114
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001115void wl12xx_queue_recovery_work(struct wl1271 *wl)
1116{
1117 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1118 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1119}
1120
Ido Yariv95dac04f2011-06-06 14:57:06 +03001121size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1122{
1123 size_t len = 0;
1124
1125 /* The FW log is a length-value list, find where the log end */
1126 while (len < maxlen) {
1127 if (memblock[len] == 0)
1128 break;
1129 if (len + memblock[len] + 1 > maxlen)
1130 break;
1131 len += memblock[len] + 1;
1132 }
1133
1134 /* Make sure we have enough room */
1135 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1136
1137 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1138 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1139 wl->fwlog_size += len;
1140
1141 return len;
1142}
1143
1144static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1145{
1146 u32 addr;
1147 u32 first_addr;
1148 u8 *block;
1149
1150 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1151 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1152 (wl->conf.fwlog.mem_blocks == 0))
1153 return;
1154
1155 wl1271_info("Reading FW panic log");
1156
1157 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1158 if (!block)
1159 return;
1160
1161 /*
1162 * Make sure the chip is awake and the logger isn't active.
1163 * This might fail if the firmware hanged.
1164 */
1165 if (!wl1271_ps_elp_wakeup(wl))
1166 wl12xx_cmd_stop_fwlog(wl);
1167
1168 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001169 wl12xx_fw_status(wl, wl->fw_status);
1170 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001171 if (!first_addr)
1172 goto out;
1173
1174 /* Traverse the memory blocks linked list */
1175 addr = first_addr;
1176 do {
1177 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1178 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1179 false);
1180
1181 /*
1182 * Memory blocks are linked to one another. The first 4 bytes
1183 * of each memory block hold the hardware address of the next
1184 * one. The last memory block points to the first one.
1185 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001186 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001187 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1188 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1189 break;
1190 } while (addr && (addr != first_addr));
1191
1192 wake_up_interruptible(&wl->fwlog_waitq);
1193
1194out:
1195 kfree(block);
1196}
1197
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001198static void wl1271_recovery_work(struct work_struct *work)
1199{
1200 struct wl1271 *wl =
1201 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001202 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001203 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001204
1205 mutex_lock(&wl->mutex);
1206
1207 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001208 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001210 /* Avoid a recursive recovery */
1211 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1212
Ido Yariv95dac04f2011-06-06 14:57:06 +03001213 wl12xx_read_fwlog_panic(wl);
1214
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001215 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1216 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001217
Eliad Peller2a5bff02011-08-25 18:10:59 +03001218 BUG_ON(bug_on_recovery);
1219
Oz Krakowskib992c682011-06-26 10:36:02 +03001220 /*
1221 * Advance security sequence number to overcome potential progress
1222 * in the firmware during recovery. This doens't hurt if the network is
1223 * not encrypted.
1224 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001225 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001226 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001227 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001228 wlvif->tx_security_seq +=
1229 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1230 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001231
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001232 /* Prevent spurious TX during FW restart */
1233 ieee80211_stop_queues(wl->hw);
1234
Luciano Coelho33c2c062011-05-10 14:46:02 +03001235 if (wl->sched_scanning) {
1236 ieee80211_sched_scan_stopped(wl->hw);
1237 wl->sched_scanning = false;
1238 }
1239
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001240 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001241 while (!list_empty(&wl->wlvif_list)) {
1242 wlvif = list_first_entry(&wl->wlvif_list,
1243 struct wl12xx_vif, list);
1244 vif = wl12xx_wlvif_to_vif(wlvif);
1245 __wl1271_op_remove_interface(wl, vif, false);
1246 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001247 mutex_unlock(&wl->mutex);
1248 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001249
1250 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1251
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001252 ieee80211_restart_hw(wl->hw);
1253
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001254 /*
1255 * Its safe to enable TX now - the queues are stopped after a request
1256 * to restart the HW.
1257 */
1258 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001259 return;
1260out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261 mutex_unlock(&wl->mutex);
1262}
1263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264static void wl1271_fw_wakeup(struct wl1271 *wl)
1265{
1266 u32 elp_reg;
1267
1268 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001269 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270}
1271
1272static int wl1271_setup(struct wl1271 *wl)
1273{
1274 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1275 if (!wl->fw_status)
1276 return -ENOMEM;
1277
1278 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1279 if (!wl->tx_res_if) {
1280 kfree(wl->fw_status);
1281 return -ENOMEM;
1282 }
1283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284 return 0;
1285}
1286
1287static int wl1271_chip_wakeup(struct wl1271 *wl)
1288{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001289 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 int ret = 0;
1291
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001292 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001293 ret = wl1271_power_on(wl);
1294 if (ret < 0)
1295 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001297 wl1271_io_reset(wl);
1298 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299
1300 /* We don't need a real memory partition here, because we only want
1301 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001302 memset(&partition, 0, sizeof(partition));
1303 partition.reg.start = REGISTERS_BASE;
1304 partition.reg.size = REGISTERS_DOWN_SIZE;
1305 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306
1307 /* ELP module wake up */
1308 wl1271_fw_wakeup(wl);
1309
1310 /* whal_FwCtrl_BootSm() */
1311
1312 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001313 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314
1315 /* 1. check if chip id is valid */
1316
1317 switch (wl->chip.id) {
1318 case CHIP_ID_1271_PG10:
1319 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1320 wl->chip.id);
1321
1322 ret = wl1271_setup(wl);
1323 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001324 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325 break;
1326 case CHIP_ID_1271_PG20:
1327 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1328 wl->chip.id);
1329
1330 ret = wl1271_setup(wl);
1331 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001332 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001334 case CHIP_ID_1283_PG20:
1335 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1336 wl->chip.id);
1337
1338 ret = wl1271_setup(wl);
1339 if (ret < 0)
1340 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001341
Ido Yariv0da13da2011-03-31 10:06:58 +02001342 if (wl1271_set_block_size(wl))
1343 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001344 break;
1345 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001347 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001349 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 }
1351
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001352 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 ret = wl1271_fetch_firmware(wl);
1354 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001355 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 }
1357
1358 /* No NVS from netlink, try to get it from the filesystem */
1359 if (wl->nvs == NULL) {
1360 ret = wl1271_fetch_nvs(wl);
1361 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001362 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 }
1364
1365out:
1366 return ret;
1367}
1368
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369int wl1271_plt_start(struct wl1271 *wl)
1370{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001372 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 int ret;
1374
1375 mutex_lock(&wl->mutex);
1376
1377 wl1271_notice("power up");
1378
1379 if (wl->state != WL1271_STATE_OFF) {
1380 wl1271_error("cannot go into PLT state because not "
1381 "in off state: %d", wl->state);
1382 ret = -EBUSY;
1383 goto out;
1384 }
1385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 while (retries) {
1387 retries--;
1388 ret = wl1271_chip_wakeup(wl);
1389 if (ret < 0)
1390 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001391
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001392 ret = wl1271_boot(wl);
1393 if (ret < 0)
1394 goto power_off;
1395
1396 ret = wl1271_plt_init(wl);
1397 if (ret < 0)
1398 goto irq_disable;
1399
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001400 wl->state = WL1271_STATE_PLT;
1401 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001402 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001403
Gery Kahn6f07b722011-07-18 14:21:49 +03001404 /* update hw/fw version info in wiphy struct */
1405 wiphy->hw_version = wl->chip.id;
1406 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1407 sizeof(wiphy->fw_version));
1408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409 goto out;
1410
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412 mutex_unlock(&wl->mutex);
1413 /* Unlocking the mutex in the middle of handling is
1414 inherently unsafe. In this case we deem it safe to do,
1415 because we need to let any possibly pending IRQ out of
1416 the system (and while we are WL1271_STATE_OFF the IRQ
1417 work function will not do anything.) Also, any other
1418 possible concurrent operations will fail due to the
1419 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001420 wl1271_disable_interrupts(wl);
1421 wl1271_flush_deferred_work(wl);
1422 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 mutex_lock(&wl->mutex);
1424power_off:
1425 wl1271_power_off(wl);
1426 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001428 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1429 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430out:
1431 mutex_unlock(&wl->mutex);
1432
1433 return ret;
1434}
1435
Luciano Coelho4623ec72011-03-21 19:26:41 +02001436static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437{
1438 int ret = 0;
1439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 wl1271_notice("power down");
1441
1442 if (wl->state != WL1271_STATE_PLT) {
1443 wl1271_error("cannot power down because not in PLT "
1444 "state: %d", wl->state);
1445 ret = -EBUSY;
1446 goto out;
1447 }
1448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449 wl1271_power_off(wl);
1450
1451 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001452 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001455 wl1271_disable_interrupts(wl);
1456 wl1271_flush_deferred_work(wl);
1457 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001458 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001459 mutex_lock(&wl->mutex);
1460out:
1461 return ret;
1462}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001463
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001464int wl1271_plt_stop(struct wl1271 *wl)
1465{
1466 int ret;
1467
1468 mutex_lock(&wl->mutex);
1469 ret = __wl1271_plt_stop(wl);
1470 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001471 return ret;
1472}
1473
Johannes Berg7bb45682011-02-24 14:42:06 +01001474static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475{
1476 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001477 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1478 struct ieee80211_vif *vif = info->control.vif;
1479 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001480 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001481 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001482 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001484 mapping = skb_get_queue_mapping(skb);
1485 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001486
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001487 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001488
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001489 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001490
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001491 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001492 if (hlid == WL12XX_INVALID_LINK_ID ||
1493 !test_bit(hlid, wlvif->links_map)) {
1494 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1495 dev_kfree_skb(skb);
1496 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001497 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001499 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1500 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1501
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001502 wl->tx_queue_count[q]++;
1503
1504 /*
1505 * The workqueue is slow to process the tx_queue and we need stop
1506 * the queue here, otherwise the queue will get too long.
1507 */
1508 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1509 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1510 ieee80211_stop_queue(wl->hw, mapping);
1511 set_bit(q, &wl->stopped_queues_map);
1512 }
1513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514 /*
1515 * The chip specific setup must run before the first TX packet -
1516 * before that, the tx_work will not be initialized!
1517 */
1518
Ido Yarivb07d4032011-03-01 15:14:43 +02001519 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1520 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001521 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001522
Arik Nemtsov04216da2011-08-14 13:17:38 +03001523out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001524 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001525}
1526
Shahar Leviae47c452011-03-06 16:32:14 +02001527int wl1271_tx_dummy_packet(struct wl1271 *wl)
1528{
Ido Yariv990f5de2011-03-31 10:06:59 +02001529 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001530 int q;
1531
1532 /* no need to queue a new dummy packet if one is already pending */
1533 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1534 return 0;
1535
1536 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001537
Ido Yariv990f5de2011-03-31 10:06:59 +02001538 spin_lock_irqsave(&wl->wl_lock, flags);
1539 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001540 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001541 spin_unlock_irqrestore(&wl->wl_lock, flags);
1542
1543 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1544 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001545 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001546
1547 /*
1548 * If the FW TX is busy, TX work will be scheduled by the threaded
1549 * interrupt handler function
1550 */
1551 return 0;
1552}
1553
1554/*
1555 * The size of the dummy packet should be at least 1400 bytes. However, in
1556 * order to minimize the number of bus transactions, aligning it to 512 bytes
1557 * boundaries could be beneficial, performance wise
1558 */
1559#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1560
Luciano Coelhocf27d862011-04-01 21:08:23 +03001561static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001562{
1563 struct sk_buff *skb;
1564 struct ieee80211_hdr_3addr *hdr;
1565 unsigned int dummy_packet_size;
1566
1567 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1568 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1569
1570 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001571 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001572 wl1271_warning("Failed to allocate a dummy packet skb");
1573 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001574 }
1575
1576 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1577
1578 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1579 memset(hdr, 0, sizeof(*hdr));
1580 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001581 IEEE80211_STYPE_NULLFUNC |
1582 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001583
Ido Yariv990f5de2011-03-31 10:06:59 +02001584 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001585
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001586 /* Dummy packets require the TID to be management */
1587 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001588
1589 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001590 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001591 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001592
Ido Yariv990f5de2011-03-31 10:06:59 +02001593 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001594}
1595
Ido Yariv990f5de2011-03-31 10:06:59 +02001596
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001597static struct notifier_block wl1271_dev_notifier = {
1598 .notifier_call = wl1271_dev_notify,
1599};
1600
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001601#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001602static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1603 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001604{
Eliad Pellere85d1622011-06-27 13:06:43 +03001605 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001606
Eliad Peller94390642011-05-13 11:57:13 +03001607 mutex_lock(&wl->mutex);
1608
Eliad Pellerba8447f2011-10-10 10:13:00 +02001609 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001610 goto out_unlock;
1611
Eliad Peller94390642011-05-13 11:57:13 +03001612 ret = wl1271_ps_elp_wakeup(wl);
1613 if (ret < 0)
1614 goto out_unlock;
1615
1616 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001617 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001618 DECLARE_COMPLETION_ONSTACK(compl);
1619
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001620 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001621 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001622 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001623 if (ret < 0)
1624 goto out_sleep;
1625
1626 /* we must unlock here so we will be able to get events */
1627 wl1271_ps_elp_sleep(wl);
1628 mutex_unlock(&wl->mutex);
1629
1630 ret = wait_for_completion_timeout(
1631 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1632 if (ret <= 0) {
1633 wl1271_warning("couldn't enter ps mode!");
1634 ret = -EBUSY;
1635 goto out;
1636 }
1637
1638 /* take mutex again, and wakeup */
1639 mutex_lock(&wl->mutex);
1640
1641 ret = wl1271_ps_elp_wakeup(wl);
1642 if (ret < 0)
1643 goto out_unlock;
1644 }
1645out_sleep:
1646 wl1271_ps_elp_sleep(wl);
1647out_unlock:
1648 mutex_unlock(&wl->mutex);
1649out:
1650 return ret;
1651
1652}
1653
Eliad Peller0603d892011-10-05 11:55:51 +02001654static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1655 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001656{
Eliad Pellere85d1622011-06-27 13:06:43 +03001657 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001658
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001659 mutex_lock(&wl->mutex);
1660
Eliad Peller53d40d02011-10-10 10:13:02 +02001661 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001662 goto out_unlock;
1663
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664 ret = wl1271_ps_elp_wakeup(wl);
1665 if (ret < 0)
1666 goto out_unlock;
1667
Eliad Peller0603d892011-10-05 11:55:51 +02001668 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001669
1670 wl1271_ps_elp_sleep(wl);
1671out_unlock:
1672 mutex_unlock(&wl->mutex);
1673 return ret;
1674
1675}
1676
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001677static int wl1271_configure_suspend(struct wl1271 *wl,
1678 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001679{
Eliad Peller536129c2011-10-05 11:55:45 +02001680 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001681 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001682 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001683 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001684 return 0;
1685}
1686
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001687static void wl1271_configure_resume(struct wl1271 *wl,
1688 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001689{
1690 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001691 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1692 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693
1694 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001695 return;
1696
1697 mutex_lock(&wl->mutex);
1698 ret = wl1271_ps_elp_wakeup(wl);
1699 if (ret < 0)
1700 goto out;
1701
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001702 if (is_sta) {
1703 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001704 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001705 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001706 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001707 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001708 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001709 }
Eliad Peller94390642011-05-13 11:57:13 +03001710
1711 wl1271_ps_elp_sleep(wl);
1712out:
1713 mutex_unlock(&wl->mutex);
1714}
1715
Eliad Peller402e48612011-05-13 11:57:09 +03001716static int wl1271_op_suspend(struct ieee80211_hw *hw,
1717 struct cfg80211_wowlan *wow)
1718{
1719 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001720 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001721 int ret;
1722
Eliad Peller402e48612011-05-13 11:57:09 +03001723 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001725
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001727 wl12xx_for_each_wlvif(wl, wlvif) {
1728 ret = wl1271_configure_suspend(wl, wlvif);
1729 if (ret < 0) {
1730 wl1271_warning("couldn't prepare device to suspend");
1731 return ret;
1732 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001733 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 /* flush any remaining work */
1735 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001736
1737 /*
1738 * disable and re-enable interrupts in order to flush
1739 * the threaded_irq
1740 */
1741 wl1271_disable_interrupts(wl);
1742
1743 /*
1744 * set suspended flag to avoid triggering a new threaded_irq
1745 * work. no need for spinlock as interrupts are disabled.
1746 */
1747 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1748
1749 wl1271_enable_interrupts(wl);
1750 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001751 wl12xx_for_each_wlvif(wl, wlvif) {
1752 flush_delayed_work(&wlvif->pspoll_work);
1753 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001754 flush_delayed_work(&wl->elp_work);
1755
Eliad Peller402e48612011-05-13 11:57:09 +03001756 return 0;
1757}
1758
1759static int wl1271_op_resume(struct ieee80211_hw *hw)
1760{
1761 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001762 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001763 unsigned long flags;
1764 bool run_irq_work = false;
1765
Eliad Peller402e48612011-05-13 11:57:09 +03001766 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1767 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001768 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001769
1770 /*
1771 * re-enable irq_work enqueuing, and call irq_work directly if
1772 * there is a pending work.
1773 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001774 spin_lock_irqsave(&wl->wl_lock, flags);
1775 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1776 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1777 run_irq_work = true;
1778 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001779
Eliad Peller4a859df2011-06-06 12:21:52 +03001780 if (run_irq_work) {
1781 wl1271_debug(DEBUG_MAC80211,
1782 "run postponed irq_work directly");
1783 wl1271_irq(0, wl);
1784 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001785 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001786 wl12xx_for_each_wlvif(wl, wlvif) {
1787 wl1271_configure_resume(wl, wlvif);
1788 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001789 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001790
Eliad Peller402e48612011-05-13 11:57:09 +03001791 return 0;
1792}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001793#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001794
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795static int wl1271_op_start(struct ieee80211_hw *hw)
1796{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001797 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1798
1799 /*
1800 * We have to delay the booting of the hardware because
1801 * we need to know the local MAC address before downloading and
1802 * initializing the firmware. The MAC address cannot be changed
1803 * after boot, and without the proper MAC address, the firmware
1804 * will not function properly.
1805 *
1806 * The MAC address is first known when the corresponding interface
1807 * is added. That is where we will initialize the hardware.
1808 */
1809
1810 return 0;
1811}
1812
1813static void wl1271_op_stop(struct ieee80211_hw *hw)
1814{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001815 struct wl1271 *wl = hw->priv;
1816 int i;
1817
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001818 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819
Eliad Peller10c8cd02011-10-10 10:13:06 +02001820 mutex_lock(&wl->mutex);
1821 if (wl->state == WL1271_STATE_OFF) {
1822 mutex_unlock(&wl->mutex);
1823 return;
1824 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001825 /*
1826 * this must be before the cancel_work calls below, so that the work
1827 * functions don't perform further work.
1828 */
1829 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001830 mutex_unlock(&wl->mutex);
1831
1832 mutex_lock(&wl_list_mutex);
1833 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001834 mutex_unlock(&wl_list_mutex);
1835
1836 wl1271_disable_interrupts(wl);
1837 wl1271_flush_deferred_work(wl);
1838 cancel_delayed_work_sync(&wl->scan_complete_work);
1839 cancel_work_sync(&wl->netstack_work);
1840 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001841 cancel_delayed_work_sync(&wl->elp_work);
1842
1843 /* let's notify MAC80211 about the remaining pending TX frames */
1844 wl12xx_tx_reset(wl, true);
1845 mutex_lock(&wl->mutex);
1846
1847 wl1271_power_off(wl);
1848
1849 wl->band = IEEE80211_BAND_2GHZ;
1850
1851 wl->rx_counter = 0;
1852 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1853 wl->tx_blocks_available = 0;
1854 wl->tx_allocated_blocks = 0;
1855 wl->tx_results_count = 0;
1856 wl->tx_packets_count = 0;
1857 wl->time_offset = 0;
1858 wl->vif = NULL;
1859 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1860 wl->ap_fw_ps_map = 0;
1861 wl->ap_ps_map = 0;
1862 wl->sched_scanning = false;
1863 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1864 memset(wl->links_map, 0, sizeof(wl->links_map));
1865 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1866 wl->active_sta_count = 0;
1867
1868 /* The system link is always allocated */
1869 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1870
1871 /*
1872 * this is performed after the cancel_work calls and the associated
1873 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1874 * get executed before all these vars have been reset.
1875 */
1876 wl->flags = 0;
1877
1878 wl->tx_blocks_freed = 0;
1879
1880 for (i = 0; i < NUM_TX_QUEUES; i++) {
1881 wl->tx_pkts_freed[i] = 0;
1882 wl->tx_allocated_pkts[i] = 0;
1883 }
1884
1885 wl1271_debugfs_reset(wl);
1886
1887 kfree(wl->fw_status);
1888 wl->fw_status = NULL;
1889 kfree(wl->tx_res_if);
1890 wl->tx_res_if = NULL;
1891 kfree(wl->target_mem_map);
1892 wl->target_mem_map = NULL;
1893
1894 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001895}
1896
Eliad Pellere5a359f2011-10-10 10:13:15 +02001897static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1898{
1899 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1900 WL12XX_MAX_RATE_POLICIES);
1901 if (policy >= WL12XX_MAX_RATE_POLICIES)
1902 return -EBUSY;
1903
1904 __set_bit(policy, wl->rate_policies_map);
1905 *idx = policy;
1906 return 0;
1907}
1908
1909static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1910{
1911 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1912 return;
1913
1914 __clear_bit(*idx, wl->rate_policies_map);
1915 *idx = WL12XX_MAX_RATE_POLICIES;
1916}
1917
Eliad Peller536129c2011-10-05 11:55:45 +02001918static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001919{
Eliad Peller536129c2011-10-05 11:55:45 +02001920 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001921 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001922 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001923 return WL1271_ROLE_P2P_GO;
1924 else
1925 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001926
1927 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001928 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001929 return WL1271_ROLE_P2P_CL;
1930 else
1931 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001932
Eliad Peller227e81e2011-08-14 13:17:26 +03001933 case BSS_TYPE_IBSS:
1934 return WL1271_ROLE_IBSS;
1935
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001936 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001937 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001938 }
1939 return WL12XX_INVALID_ROLE_TYPE;
1940}
1941
Eliad Peller83587502011-10-10 10:12:53 +02001942static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001943{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001944 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001945 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001946
Eliad Peller48e93e42011-10-10 10:12:58 +02001947 /* clear everything but the persistent data */
1948 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001949
1950 switch (ieee80211_vif_type_p2p(vif)) {
1951 case NL80211_IFTYPE_P2P_CLIENT:
1952 wlvif->p2p = 1;
1953 /* fall-through */
1954 case NL80211_IFTYPE_STATION:
1955 wlvif->bss_type = BSS_TYPE_STA_BSS;
1956 break;
1957 case NL80211_IFTYPE_ADHOC:
1958 wlvif->bss_type = BSS_TYPE_IBSS;
1959 break;
1960 case NL80211_IFTYPE_P2P_GO:
1961 wlvif->p2p = 1;
1962 /* fall-through */
1963 case NL80211_IFTYPE_AP:
1964 wlvif->bss_type = BSS_TYPE_AP_BSS;
1965 break;
1966 default:
1967 wlvif->bss_type = MAX_BSS_TYPE;
1968 return -EOPNOTSUPP;
1969 }
1970
Eliad Peller0603d892011-10-05 11:55:51 +02001971 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001972 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001973 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001974
Eliad Pellere936bbe2011-10-05 11:55:56 +02001975 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1976 wlvif->bss_type == BSS_TYPE_IBSS) {
1977 /* init sta/ibss data */
1978 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001979 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1980 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1981 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001982 } else {
1983 /* init ap data */
1984 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1985 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001986 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1987 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1988 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1989 wl12xx_allocate_rate_policy(wl,
1990 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001991 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001992
Eliad Peller83587502011-10-10 10:12:53 +02001993 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1994 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001995 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001996 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001997 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001998 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1999
Eliad Peller1b92f152011-10-10 10:13:09 +02002000 /*
2001 * mac80211 configures some values globally, while we treat them
2002 * per-interface. thus, on init, we have to copy them from wl
2003 */
2004 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002005 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002006 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002007
Eliad Peller9eb599e2011-10-10 10:12:59 +02002008 INIT_WORK(&wlvif->rx_streaming_enable_work,
2009 wl1271_rx_streaming_enable_work);
2010 INIT_WORK(&wlvif->rx_streaming_disable_work,
2011 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002012 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002013 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002014
Eliad Peller9eb599e2011-10-10 10:12:59 +02002015 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2016 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002017 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002018}
2019
Eliad Peller1d095472011-10-10 10:12:49 +02002020static bool wl12xx_init_fw(struct wl1271 *wl)
2021{
2022 int retries = WL1271_BOOT_RETRIES;
2023 bool booted = false;
2024 struct wiphy *wiphy = wl->hw->wiphy;
2025 int ret;
2026
2027 while (retries) {
2028 retries--;
2029 ret = wl1271_chip_wakeup(wl);
2030 if (ret < 0)
2031 goto power_off;
2032
2033 ret = wl1271_boot(wl);
2034 if (ret < 0)
2035 goto power_off;
2036
2037 ret = wl1271_hw_init(wl);
2038 if (ret < 0)
2039 goto irq_disable;
2040
2041 booted = true;
2042 break;
2043
2044irq_disable:
2045 mutex_unlock(&wl->mutex);
2046 /* Unlocking the mutex in the middle of handling is
2047 inherently unsafe. In this case we deem it safe to do,
2048 because we need to let any possibly pending IRQ out of
2049 the system (and while we are WL1271_STATE_OFF the IRQ
2050 work function will not do anything.) Also, any other
2051 possible concurrent operations will fail due to the
2052 current state, hence the wl1271 struct should be safe. */
2053 wl1271_disable_interrupts(wl);
2054 wl1271_flush_deferred_work(wl);
2055 cancel_work_sync(&wl->netstack_work);
2056 mutex_lock(&wl->mutex);
2057power_off:
2058 wl1271_power_off(wl);
2059 }
2060
2061 if (!booted) {
2062 wl1271_error("firmware boot failed despite %d retries",
2063 WL1271_BOOT_RETRIES);
2064 goto out;
2065 }
2066
2067 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2068
2069 /* update hw/fw version info in wiphy struct */
2070 wiphy->hw_version = wl->chip.id;
2071 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2072 sizeof(wiphy->fw_version));
2073
2074 /*
2075 * Now we know if 11a is supported (info from the NVS), so disable
2076 * 11a channels if not supported
2077 */
2078 if (!wl->enable_11a)
2079 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2080
2081 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2082 wl->enable_11a ? "" : "not ");
2083
2084 wl->state = WL1271_STATE_ON;
2085out:
2086 return booted;
2087}
2088
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002089static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2090 struct ieee80211_vif *vif)
2091{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002092 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002093 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002095 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002096 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002097
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002098 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002099 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
2101 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002102 ret = wl1271_ps_elp_wakeup(wl);
2103 if (ret < 0)
2104 goto out_unlock;
2105
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002106 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002107 wl1271_debug(DEBUG_MAC80211,
2108 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002109 ret = -EBUSY;
2110 goto out;
2111 }
2112
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002113 /*
2114 * in some very corner case HW recovery scenarios its possible to
2115 * get here before __wl1271_op_remove_interface is complete, so
2116 * opt out if that is the case.
2117 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002118 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2119 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002120 ret = -EBUSY;
2121 goto out;
2122 }
2123
Eliad Peller83587502011-10-10 10:12:53 +02002124 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002125 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002126 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002127
Eliad Peller252efa42011-10-05 11:56:00 +02002128 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002129 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002130 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2131 ret = -EINVAL;
2132 goto out;
2133 }
Eliad Peller1d095472011-10-10 10:12:49 +02002134
Eliad Peller784f6942011-10-05 11:55:39 +02002135 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002136 * TODO: after the nvs issue will be solved, move this block
2137 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002138 */
Eliad Peller1d095472011-10-10 10:12:49 +02002139 if (wl->state == WL1271_STATE_OFF) {
2140 /*
2141 * we still need this in order to configure the fw
2142 * while uploading the nvs
2143 */
2144 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145
Eliad Peller1d095472011-10-10 10:12:49 +02002146 booted = wl12xx_init_fw(wl);
2147 if (!booted) {
2148 ret = -EINVAL;
2149 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002150 }
Eliad Peller1d095472011-10-10 10:12:49 +02002151 }
Eliad Peller04e80792011-08-14 13:17:09 +03002152
Eliad Peller1d095472011-10-10 10:12:49 +02002153 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2154 wlvif->bss_type == BSS_TYPE_IBSS) {
2155 /*
2156 * The device role is a special role used for
2157 * rx and tx frames prior to association (as
2158 * the STA role can get packets only from
2159 * its associated bssid)
2160 */
Eliad Peller784f6942011-10-05 11:55:39 +02002161 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002162 WL1271_ROLE_DEVICE,
2163 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002164 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002165 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002166 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167
Eliad Peller1d095472011-10-10 10:12:49 +02002168 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2169 role_type, &wlvif->role_id);
2170 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002171 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002172
2173 ret = wl1271_init_vif_specific(wl, vif);
2174 if (ret < 0)
2175 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002176
2177 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002178 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002179 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002180
2181 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2182 wl->ap_count++;
2183 else
2184 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002185out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002186 wl1271_ps_elp_sleep(wl);
2187out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002188 mutex_unlock(&wl->mutex);
2189
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002190 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002191 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002192 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002193 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002194
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195 return ret;
2196}
2197
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002198static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002199 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002200 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201{
Eliad Peller536129c2011-10-05 11:55:45 +02002202 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002203 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002205 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206
Eliad Peller10c8cd02011-10-10 10:13:06 +02002207 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2208 return;
2209
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002210 /* because of hardware recovery, we may get here twice */
2211 if (wl->state != WL1271_STATE_ON)
2212 return;
2213
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002214 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002216 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002217 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002218 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002219
Eliad Pellerbaf62772011-10-10 10:12:52 +02002220 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2221 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002222 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002223 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002224 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002225 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002226 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002227 }
2228
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002229 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2230 /* disable active roles */
2231 ret = wl1271_ps_elp_wakeup(wl);
2232 if (ret < 0)
2233 goto deinit;
2234
Eliad Peller536129c2011-10-05 11:55:45 +02002235 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002236 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002237 if (ret < 0)
2238 goto deinit;
2239 }
2240
Eliad Peller0603d892011-10-05 11:55:51 +02002241 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002242 if (ret < 0)
2243 goto deinit;
2244
2245 wl1271_ps_elp_sleep(wl);
2246 }
2247deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002248 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002249 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002250
2251 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2252 wlvif->bss_type == BSS_TYPE_IBSS) {
2253 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2254 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2255 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2256 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2257 } else {
2258 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2259 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2260 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2261 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2262 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2263 wl12xx_free_rate_policy(wl,
2264 &wlvif->ap.ucast_rate_idx[i]);
2265 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002266
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002267 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002268 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002269 if (wl->last_wlvif == wlvif)
2270 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002271 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002272 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002273 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002274 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002275
Eliad Pellera4e41302011-10-11 11:49:15 +02002276 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2277 wl->ap_count--;
2278 else
2279 wl->sta_count--;
2280
Eliad Pellerbaf62772011-10-10 10:12:52 +02002281 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002282 del_timer_sync(&wlvif->rx_streaming_timer);
2283 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2284 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002285 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002286
Eliad Pellerbaf62772011-10-10 10:12:52 +02002287 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002288}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002289
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002290static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2291 struct ieee80211_vif *vif)
2292{
2293 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002294 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002295 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002296
2297 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002298
2299 if (wl->state == WL1271_STATE_OFF ||
2300 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2301 goto out;
2302
Juuso Oikarinen67353292010-11-18 15:19:02 +02002303 /*
2304 * wl->vif can be null here if someone shuts down the interface
2305 * just when hardware recovery has been started.
2306 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002307 wl12xx_for_each_wlvif(wl, iter) {
2308 if (iter != wlvif)
2309 continue;
2310
Eliad Peller536129c2011-10-05 11:55:45 +02002311 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002312 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002313 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002314 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002315out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002316 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002317 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318}
2319
Eliad Peller87fbcb02011-10-05 11:55:41 +02002320static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2321 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002322{
2323 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002324 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002325
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002326 /*
2327 * One of the side effects of the JOIN command is that is clears
2328 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2329 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002330 * Currently the only valid scenario for JOIN during association
2331 * is on roaming, in which case we will also be given new keys.
2332 * Keep the below message for now, unless it starts bothering
2333 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002334 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002335 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002336 wl1271_info("JOIN while associated.");
2337
2338 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002339 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002340
Eliad Peller227e81e2011-08-14 13:17:26 +03002341 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002342 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002343 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002344 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002345 if (ret < 0)
2346 goto out;
2347
Eliad Pellerba8447f2011-10-10 10:13:00 +02002348 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002349 goto out;
2350
2351 /*
2352 * The join command disable the keep-alive mode, shut down its process,
2353 * and also clear the template config, so we need to reset it all after
2354 * the join. The acx_aid starts the keep-alive process, and the order
2355 * of the commands below is relevant.
2356 */
Eliad Peller0603d892011-10-05 11:55:51 +02002357 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002358 if (ret < 0)
2359 goto out;
2360
Eliad Peller0603d892011-10-05 11:55:51 +02002361 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002362 if (ret < 0)
2363 goto out;
2364
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002365 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 if (ret < 0)
2367 goto out;
2368
Eliad Peller0603d892011-10-05 11:55:51 +02002369 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2370 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002371 ACX_KEEP_ALIVE_TPL_VALID);
2372 if (ret < 0)
2373 goto out;
2374
2375out:
2376 return ret;
2377}
2378
Eliad Peller0603d892011-10-05 11:55:51 +02002379static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002380{
2381 int ret;
2382
Eliad Peller52630c52011-10-10 10:13:08 +02002383 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002384 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2385
Shahar Levi6d158ff2011-09-08 13:01:33 +03002386 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002387 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002388 }
2389
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002390 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002391 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002392 if (ret < 0)
2393 goto out;
2394
Oz Krakowskib992c682011-06-26 10:36:02 +03002395 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002396 wlvif->tx_security_last_seq_lsb = 0;
2397 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002398
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002399out:
2400 return ret;
2401}
2402
Eliad Peller87fbcb02011-10-05 11:55:41 +02002403static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404{
Eliad Peller1b92f152011-10-10 10:13:09 +02002405 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002406 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002407}
2408
Eliad Peller251c1772011-08-14 13:17:17 +03002409static bool wl12xx_is_roc(struct wl1271 *wl)
2410{
2411 u8 role_id;
2412
2413 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2414 if (role_id >= WL12XX_MAX_ROLES)
2415 return false;
2416
2417 return true;
2418}
2419
Eliad Peller87fbcb02011-10-05 11:55:41 +02002420static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2421 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002422{
2423 int ret;
2424
2425 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002426 /* no need to croc if we weren't busy (e.g. during boot) */
2427 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002428 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002429 if (ret < 0)
2430 goto out;
2431
Eliad Peller7edebf52011-10-05 11:55:52 +02002432 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002433 if (ret < 0)
2434 goto out;
2435 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002436 wlvif->rate_set =
2437 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2438 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002439 if (ret < 0)
2440 goto out;
2441 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002442 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002443 ACX_KEEP_ALIVE_TPL_INVALID);
2444 if (ret < 0)
2445 goto out;
2446 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2447 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002448 /* The current firmware only supports sched_scan in idle */
2449 if (wl->sched_scanning) {
2450 wl1271_scan_sched_scan_stop(wl);
2451 ieee80211_sched_scan_stopped(wl->hw);
2452 }
2453
Eliad Peller7edebf52011-10-05 11:55:52 +02002454 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002455 if (ret < 0)
2456 goto out;
2457
Eliad Peller1b92f152011-10-10 10:13:09 +02002458 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002459 if (ret < 0)
2460 goto out;
2461 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2462 }
2463
2464out:
2465 return ret;
2466}
2467
Eliad Peller9f259c42011-10-10 10:13:12 +02002468static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2469 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470{
Eliad Peller9f259c42011-10-10 10:13:12 +02002471 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2472 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473
2474 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2475
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002476 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002477 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002478 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002479 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002480 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002481 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002482 wlvif->band = conf->channel->band;
2483 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002484
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002485 if (!is_ap) {
2486 /*
2487 * FIXME: the mac80211 should really provide a fixed
2488 * rate to use here. for now, just use the smallest
2489 * possible rate for the band as a fixed rate for
2490 * association frames and other control messages.
2491 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002492 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002493 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002494
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002495 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002496 wl1271_tx_min_rate_get(wl,
2497 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002498 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002499 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002500 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002501 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002502
Eliad Pellerba8447f2011-10-10 10:13:00 +02002503 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2504 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002505 if (wl12xx_is_roc(wl)) {
2506 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002507 ret = wl12xx_croc(wl,
2508 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002509 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002510 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002511 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002512 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002513 if (ret < 0)
2514 wl1271_warning("cmd join on channel "
2515 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002516 } else {
2517 /*
2518 * change the ROC channel. do it only if we are
2519 * not idle. otherwise, CROC will be called
2520 * anyway.
2521 */
2522 if (wl12xx_is_roc(wl) &&
2523 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002524 ret = wl12xx_croc(wl,
2525 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002526 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002527 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002528
Eliad Peller1b92f152011-10-10 10:13:09 +02002529 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002530 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002531 if (ret < 0)
2532 wl1271_warning("roc failed %d",
2533 ret);
2534 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002535 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002536 }
2537 }
2538
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002539 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002540 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002541 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002542 if (ret < 0)
2543 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 }
2545
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002546 /*
2547 * if mac80211 changes the PSM mode, make sure the mode is not
2548 * incorrectly changed after the pspoll failure active window.
2549 */
2550 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002551 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002552
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002553 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002554 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2555 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
2557 /*
2558 * We enter PSM only if we're already associated.
2559 * If we're not, we'll enter it when joining an SSID,
2560 * through the bss_info_changed() hook.
2561 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002562 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002563 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002564 ret = wl1271_ps_set_mode(wl, wlvif,
2565 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002566 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002567 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002568 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002569 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002570 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571
Eliad Pellerc29bb002011-10-10 10:13:03 +02002572 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002573
Eliad Pellerc29bb002011-10-10 10:13:03 +02002574 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002575 ret = wl1271_ps_set_mode(wl, wlvif,
2576 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002577 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578 }
2579
Eliad Peller6bd65022011-10-10 10:13:11 +02002580 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002581 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002583 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584
Eliad Peller6bd65022011-10-10 10:13:11 +02002585 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 }
2587
Eliad Peller9f259c42011-10-10 10:13:12 +02002588 return 0;
2589}
2590
2591static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2592{
2593 struct wl1271 *wl = hw->priv;
2594 struct wl12xx_vif *wlvif;
2595 struct ieee80211_conf *conf = &hw->conf;
2596 int channel, ret = 0;
2597
2598 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2599
2600 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2601 " changed 0x%x",
2602 channel,
2603 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2604 conf->power_level,
2605 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2606 changed);
2607
2608 /*
2609 * mac80211 will go to idle nearly immediately after transmitting some
2610 * frames, such as the deauth. To make sure those frames reach the air,
2611 * wait here until the TX queue is fully flushed.
2612 */
2613 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2614 (conf->flags & IEEE80211_CONF_IDLE))
2615 wl1271_tx_flush(wl);
2616
2617 mutex_lock(&wl->mutex);
2618
2619 /* we support configuring the channel and band even while off */
2620 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2621 wl->band = conf->channel->band;
2622 wl->channel = channel;
2623 }
2624
2625 if (changed & IEEE80211_CONF_CHANGE_POWER)
2626 wl->power_level = conf->power_level;
2627
2628 if (unlikely(wl->state == WL1271_STATE_OFF))
2629 goto out;
2630
2631 ret = wl1271_ps_elp_wakeup(wl);
2632 if (ret < 0)
2633 goto out;
2634
2635 /* configure each interface */
2636 wl12xx_for_each_wlvif(wl, wlvif) {
2637 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2638 if (ret < 0)
2639 goto out_sleep;
2640 }
2641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002642out_sleep:
2643 wl1271_ps_elp_sleep(wl);
2644
2645out:
2646 mutex_unlock(&wl->mutex);
2647
2648 return ret;
2649}
2650
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002651struct wl1271_filter_params {
2652 bool enabled;
2653 int mc_list_length;
2654 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2655};
2656
Jiri Pirko22bedad2010-04-01 21:22:57 +00002657static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2658 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002659{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002660 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002661 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002662 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002663
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002664 if (unlikely(wl->state == WL1271_STATE_OFF))
2665 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002666
Juuso Oikarinen74441132009-10-13 12:47:53 +03002667 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 if (!fp) {
2669 wl1271_error("Out of memory setting filters.");
2670 return 0;
2671 }
2672
2673 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002674 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002675 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2676 fp->enabled = false;
2677 } else {
2678 fp->enabled = true;
2679 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002680 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002681 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002682 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002683 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002684 }
2685
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002686 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002687}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002688
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002689#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2690 FIF_ALLMULTI | \
2691 FIF_FCSFAIL | \
2692 FIF_BCN_PRBRESP_PROMISC | \
2693 FIF_CONTROL | \
2694 FIF_OTHER_BSS)
2695
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2697 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002698 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002700 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002702 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002703
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002704 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705
Arik Nemtsov7d057862010-10-16 19:25:35 +02002706 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2707 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002709 mutex_lock(&wl->mutex);
2710
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002711 *total &= WL1271_SUPPORTED_FILTERS;
2712 changed &= WL1271_SUPPORTED_FILTERS;
2713
2714 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002715 goto out;
2716
Ido Yariva6208652011-03-01 15:14:41 +02002717 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002718 if (ret < 0)
2719 goto out;
2720
Eliad Peller6e8cd332011-10-10 10:13:13 +02002721 wl12xx_for_each_wlvif(wl, wlvif) {
2722 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2723 if (*total & FIF_ALLMULTI)
2724 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2725 false,
2726 NULL, 0);
2727 else if (fp)
2728 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2729 fp->enabled,
2730 fp->mc_list,
2731 fp->mc_list_length);
2732 if (ret < 0)
2733 goto out_sleep;
2734 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002735 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002737 /*
2738 * the fw doesn't provide an api to configure the filters. instead,
2739 * the filters configuration is based on the active roles / ROC
2740 * state.
2741 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002742
2743out_sleep:
2744 wl1271_ps_elp_sleep(wl);
2745
2746out:
2747 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002748 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749}
2750
Eliad Peller170d0e62011-10-05 11:56:06 +02002751static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2752 u8 id, u8 key_type, u8 key_size,
2753 const u8 *key, u8 hlid, u32 tx_seq_32,
2754 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002755{
2756 struct wl1271_ap_key *ap_key;
2757 int i;
2758
2759 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2760
2761 if (key_size > MAX_KEY_SIZE)
2762 return -EINVAL;
2763
2764 /*
2765 * Find next free entry in ap_keys. Also check we are not replacing
2766 * an existing key.
2767 */
2768 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002769 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002770 break;
2771
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002773 wl1271_warning("trying to record key replacement");
2774 return -EINVAL;
2775 }
2776 }
2777
2778 if (i == MAX_NUM_KEYS)
2779 return -EBUSY;
2780
2781 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2782 if (!ap_key)
2783 return -ENOMEM;
2784
2785 ap_key->id = id;
2786 ap_key->key_type = key_type;
2787 ap_key->key_size = key_size;
2788 memcpy(ap_key->key, key, key_size);
2789 ap_key->hlid = hlid;
2790 ap_key->tx_seq_32 = tx_seq_32;
2791 ap_key->tx_seq_16 = tx_seq_16;
2792
Eliad Peller170d0e62011-10-05 11:56:06 +02002793 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794 return 0;
2795}
2796
Eliad Peller170d0e62011-10-05 11:56:06 +02002797static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798{
2799 int i;
2800
2801 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002802 kfree(wlvif->ap.recorded_keys[i]);
2803 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002804 }
2805}
2806
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002807static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808{
2809 int i, ret = 0;
2810 struct wl1271_ap_key *key;
2811 bool wep_key_added = false;
2812
2813 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002814 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002815 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002816 break;
2817
Eliad Peller170d0e62011-10-05 11:56:06 +02002818 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002819 hlid = key->hlid;
2820 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002821 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002822
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002823 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 key->id, key->key_type,
2825 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002826 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 key->tx_seq_16);
2828 if (ret < 0)
2829 goto out;
2830
2831 if (key->key_type == KEY_WEP)
2832 wep_key_added = true;
2833 }
2834
2835 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002836 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002837 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002838 if (ret < 0)
2839 goto out;
2840 }
2841
2842out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002843 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002844 return ret;
2845}
2846
Eliad Peller536129c2011-10-05 11:55:45 +02002847static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2848 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002849 u8 key_size, const u8 *key, u32 tx_seq_32,
2850 u16 tx_seq_16, struct ieee80211_sta *sta)
2851{
2852 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002853 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002854
2855 if (is_ap) {
2856 struct wl1271_station *wl_sta;
2857 u8 hlid;
2858
2859 if (sta) {
2860 wl_sta = (struct wl1271_station *)sta->drv_priv;
2861 hlid = wl_sta->hlid;
2862 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002863 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002864 }
2865
Eliad Peller53d40d02011-10-10 10:13:02 +02002866 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002867 /*
2868 * We do not support removing keys after AP shutdown.
2869 * Pretend we do to make mac80211 happy.
2870 */
2871 if (action != KEY_ADD_OR_REPLACE)
2872 return 0;
2873
Eliad Peller170d0e62011-10-05 11:56:06 +02002874 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002875 key_type, key_size,
2876 key, hlid, tx_seq_32,
2877 tx_seq_16);
2878 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002879 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002880 id, key_type, key_size,
2881 key, hlid, tx_seq_32,
2882 tx_seq_16);
2883 }
2884
2885 if (ret < 0)
2886 return ret;
2887 } else {
2888 const u8 *addr;
2889 static const u8 bcast_addr[ETH_ALEN] = {
2890 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2891 };
2892
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002893 /*
2894 * A STA set to GEM cipher requires 2 tx spare blocks.
2895 * Return to default value when GEM cipher key is removed
2896 */
2897 if (key_type == KEY_GEM) {
2898 if (action == KEY_ADD_OR_REPLACE)
2899 wl->tx_spare_blocks = 2;
2900 else if (action == KEY_REMOVE)
2901 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2902 }
2903
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002904 addr = sta ? sta->addr : bcast_addr;
2905
2906 if (is_zero_ether_addr(addr)) {
2907 /* We dont support TX only encryption */
2908 return -EOPNOTSUPP;
2909 }
2910
2911 /* The wl1271 does not allow to remove unicast keys - they
2912 will be cleared automatically on next CMD_JOIN. Ignore the
2913 request silently, as we dont want the mac80211 to emit
2914 an error message. */
2915 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2916 return 0;
2917
Eliad Peller010d3d32011-08-14 13:17:31 +03002918 /* don't remove key if hlid was already deleted */
2919 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002920 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002921 return 0;
2922
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002923 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002924 id, key_type, key_size,
2925 key, addr, tx_seq_32,
2926 tx_seq_16);
2927 if (ret < 0)
2928 return ret;
2929
2930 /* the default WEP key needs to be configured at least once */
2931 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002932 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002933 wlvif->default_key,
2934 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002935 if (ret < 0)
2936 return ret;
2937 }
2938 }
2939
2940 return 0;
2941}
2942
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2944 struct ieee80211_vif *vif,
2945 struct ieee80211_sta *sta,
2946 struct ieee80211_key_conf *key_conf)
2947{
2948 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002949 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002951 u32 tx_seq_32 = 0;
2952 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 u8 key_type;
2954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2956
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002957 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002959 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 key_conf->keylen, key_conf->flags);
2961 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2962
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 mutex_lock(&wl->mutex);
2964
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002965 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2966 ret = -EAGAIN;
2967 goto out_unlock;
2968 }
2969
Ido Yariva6208652011-03-01 15:14:41 +02002970 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 if (ret < 0)
2972 goto out_unlock;
2973
Johannes Berg97359d12010-08-10 09:46:38 +02002974 switch (key_conf->cipher) {
2975 case WLAN_CIPHER_SUITE_WEP40:
2976 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977 key_type = KEY_WEP;
2978
2979 key_conf->hw_key_idx = key_conf->keyidx;
2980 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002981 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002982 key_type = KEY_TKIP;
2983
2984 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002985 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2986 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002988 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002989 key_type = KEY_AES;
2990
2991 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002992 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2993 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002995 case WL1271_CIPHER_SUITE_GEM:
2996 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002997 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2998 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002999 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003001 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002
3003 ret = -EOPNOTSUPP;
3004 goto out_sleep;
3005 }
3006
3007 switch (cmd) {
3008 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003009 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003010 key_conf->keyidx, key_type,
3011 key_conf->keylen, key_conf->key,
3012 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003013 if (ret < 0) {
3014 wl1271_error("Could not add or replace key");
3015 goto out_sleep;
3016 }
3017 break;
3018
3019 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003020 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003021 key_conf->keyidx, key_type,
3022 key_conf->keylen, key_conf->key,
3023 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003024 if (ret < 0) {
3025 wl1271_error("Could not remove key");
3026 goto out_sleep;
3027 }
3028 break;
3029
3030 default:
3031 wl1271_error("Unsupported key cmd 0x%x", cmd);
3032 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033 break;
3034 }
3035
3036out_sleep:
3037 wl1271_ps_elp_sleep(wl);
3038
3039out_unlock:
3040 mutex_unlock(&wl->mutex);
3041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003042 return ret;
3043}
3044
3045static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003046 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047 struct cfg80211_scan_request *req)
3048{
3049 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003050 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003052 int ret;
3053 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003054 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003055
3056 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3057
3058 if (req->n_ssids) {
3059 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003060 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 }
3062
3063 mutex_lock(&wl->mutex);
3064
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003065 if (wl->state == WL1271_STATE_OFF) {
3066 /*
3067 * We cannot return -EBUSY here because cfg80211 will expect
3068 * a call to ieee80211_scan_completed if we do - in this case
3069 * there won't be any call.
3070 */
3071 ret = -EAGAIN;
3072 goto out;
3073 }
3074
Ido Yariva6208652011-03-01 15:14:41 +02003075 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003076 if (ret < 0)
3077 goto out;
3078
Eliad Peller251c1772011-08-14 13:17:17 +03003079 /* cancel ROC before scanning */
3080 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003081 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003082 /* don't allow scanning right now */
3083 ret = -EBUSY;
3084 goto out_sleep;
3085 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003086 wl12xx_croc(wl, wlvif->dev_role_id);
3087 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003088 }
3089
Eliad Peller784f6942011-10-05 11:55:39 +02003090 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003091out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003092 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003093out:
3094 mutex_unlock(&wl->mutex);
3095
3096 return ret;
3097}
3098
Eliad Peller73ecce32011-06-27 13:06:45 +03003099static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3100 struct ieee80211_vif *vif)
3101{
3102 struct wl1271 *wl = hw->priv;
3103 int ret;
3104
3105 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3106
3107 mutex_lock(&wl->mutex);
3108
3109 if (wl->state == WL1271_STATE_OFF)
3110 goto out;
3111
3112 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3113 goto out;
3114
3115 ret = wl1271_ps_elp_wakeup(wl);
3116 if (ret < 0)
3117 goto out;
3118
3119 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3120 ret = wl1271_scan_stop(wl);
3121 if (ret < 0)
3122 goto out_sleep;
3123 }
3124 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3125 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003126 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003127 wl->scan.req = NULL;
3128 ieee80211_scan_completed(wl->hw, true);
3129
3130out_sleep:
3131 wl1271_ps_elp_sleep(wl);
3132out:
3133 mutex_unlock(&wl->mutex);
3134
3135 cancel_delayed_work_sync(&wl->scan_complete_work);
3136}
3137
Luciano Coelho33c2c062011-05-10 14:46:02 +03003138static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3139 struct ieee80211_vif *vif,
3140 struct cfg80211_sched_scan_request *req,
3141 struct ieee80211_sched_scan_ies *ies)
3142{
3143 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003144 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003145 int ret;
3146
3147 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3148
3149 mutex_lock(&wl->mutex);
3150
3151 ret = wl1271_ps_elp_wakeup(wl);
3152 if (ret < 0)
3153 goto out;
3154
Eliad Peller536129c2011-10-05 11:55:45 +02003155 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003156 if (ret < 0)
3157 goto out_sleep;
3158
Eliad Peller536129c2011-10-05 11:55:45 +02003159 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003160 if (ret < 0)
3161 goto out_sleep;
3162
3163 wl->sched_scanning = true;
3164
3165out_sleep:
3166 wl1271_ps_elp_sleep(wl);
3167out:
3168 mutex_unlock(&wl->mutex);
3169 return ret;
3170}
3171
3172static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3173 struct ieee80211_vif *vif)
3174{
3175 struct wl1271 *wl = hw->priv;
3176 int ret;
3177
3178 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3179
3180 mutex_lock(&wl->mutex);
3181
3182 ret = wl1271_ps_elp_wakeup(wl);
3183 if (ret < 0)
3184 goto out;
3185
3186 wl1271_scan_sched_scan_stop(wl);
3187
3188 wl1271_ps_elp_sleep(wl);
3189out:
3190 mutex_unlock(&wl->mutex);
3191}
3192
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003193static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3194{
3195 struct wl1271 *wl = hw->priv;
3196 int ret = 0;
3197
3198 mutex_lock(&wl->mutex);
3199
3200 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3201 ret = -EAGAIN;
3202 goto out;
3203 }
3204
Ido Yariva6208652011-03-01 15:14:41 +02003205 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003206 if (ret < 0)
3207 goto out;
3208
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003209 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003210 if (ret < 0)
3211 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3212
3213 wl1271_ps_elp_sleep(wl);
3214
3215out:
3216 mutex_unlock(&wl->mutex);
3217
3218 return ret;
3219}
3220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003221static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3222{
3223 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003224 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003225 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226
3227 mutex_lock(&wl->mutex);
3228
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003229 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3230 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003231 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003232 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003233
Ido Yariva6208652011-03-01 15:14:41 +02003234 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 if (ret < 0)
3236 goto out;
3237
Eliad Peller6e8cd332011-10-10 10:13:13 +02003238 wl12xx_for_each_wlvif(wl, wlvif) {
3239 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3240 if (ret < 0)
3241 wl1271_warning("set rts threshold failed: %d", ret);
3242 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243 wl1271_ps_elp_sleep(wl);
3244
3245out:
3246 mutex_unlock(&wl->mutex);
3247
3248 return ret;
3249}
3250
Eliad Peller1fe9f162011-10-05 11:55:48 +02003251static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003252 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003253{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003254 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003255 u8 ssid_len;
3256 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3257 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003258
Eliad Peller889cb362011-05-01 09:56:45 +03003259 if (!ptr) {
3260 wl1271_error("No SSID in IEs!");
3261 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003262 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003263
Eliad Peller889cb362011-05-01 09:56:45 +03003264 ssid_len = ptr[1];
3265 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3266 wl1271_error("SSID is too long!");
3267 return -EINVAL;
3268 }
3269
Eliad Peller1fe9f162011-10-05 11:55:48 +02003270 wlvif->ssid_len = ssid_len;
3271 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003272 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003273}
3274
Eliad Pellerd48055d2011-09-15 12:07:04 +03003275static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3276{
3277 int len;
3278 const u8 *next, *end = skb->data + skb->len;
3279 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3280 skb->len - ieoffset);
3281 if (!ie)
3282 return;
3283 len = ie[1] + 2;
3284 next = ie + len;
3285 memmove(ie, next, end - next);
3286 skb_trim(skb, skb->len - len);
3287}
3288
Eliad Peller26b4bf22011-09-15 12:07:05 +03003289static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3290 unsigned int oui, u8 oui_type,
3291 int ieoffset)
3292{
3293 int len;
3294 const u8 *next, *end = skb->data + skb->len;
3295 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3296 skb->data + ieoffset,
3297 skb->len - ieoffset);
3298 if (!ie)
3299 return;
3300 len = ie[1] + 2;
3301 next = ie + len;
3302 memmove(ie, next, end - next);
3303 skb_trim(skb, skb->len - len);
3304}
3305
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003306static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003307 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003308 u8 *probe_rsp_data,
3309 size_t probe_rsp_len,
3310 u32 rates)
3311{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003312 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3313 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003314 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3315 int ssid_ie_offset, ie_offset, templ_len;
3316 const u8 *ptr;
3317
3318 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003319 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003320 return wl1271_cmd_template_set(wl,
3321 CMD_TEMPL_AP_PROBE_RESPONSE,
3322 probe_rsp_data,
3323 probe_rsp_len, 0,
3324 rates);
3325
3326 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3327 wl1271_error("probe_rsp template too big");
3328 return -EINVAL;
3329 }
3330
3331 /* start searching from IE offset */
3332 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3333
3334 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3335 probe_rsp_len - ie_offset);
3336 if (!ptr) {
3337 wl1271_error("No SSID in beacon!");
3338 return -EINVAL;
3339 }
3340
3341 ssid_ie_offset = ptr - probe_rsp_data;
3342 ptr += (ptr[1] + 2);
3343
3344 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3345
3346 /* insert SSID from bss_conf */
3347 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3348 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3349 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3350 bss_conf->ssid, bss_conf->ssid_len);
3351 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3352
3353 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3354 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3355 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3356
3357 return wl1271_cmd_template_set(wl,
3358 CMD_TEMPL_AP_PROBE_RESPONSE,
3359 probe_rsp_templ,
3360 templ_len, 0,
3361 rates);
3362}
3363
Arik Nemtsove78a2872010-10-16 19:07:21 +02003364static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003365 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 struct ieee80211_bss_conf *bss_conf,
3367 u32 changed)
3368{
Eliad Peller0603d892011-10-05 11:55:51 +02003369 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 int ret = 0;
3371
3372 if (changed & BSS_CHANGED_ERP_SLOT) {
3373 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003374 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 else
Eliad Peller0603d892011-10-05 11:55:51 +02003376 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 if (ret < 0) {
3378 wl1271_warning("Set slot time failed %d", ret);
3379 goto out;
3380 }
3381 }
3382
3383 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3384 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003385 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 else
Eliad Peller0603d892011-10-05 11:55:51 +02003387 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 }
3389
3390 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3391 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003392 ret = wl1271_acx_cts_protect(wl, wlvif,
3393 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 else
Eliad Peller0603d892011-10-05 11:55:51 +02003395 ret = wl1271_acx_cts_protect(wl, wlvif,
3396 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 if (ret < 0) {
3398 wl1271_warning("Set ctsprotect failed %d", ret);
3399 goto out;
3400 }
3401 }
3402
3403out:
3404 return ret;
3405}
3406
3407static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3408 struct ieee80211_vif *vif,
3409 struct ieee80211_bss_conf *bss_conf,
3410 u32 changed)
3411{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003412 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003413 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 int ret = 0;
3415
3416 if ((changed & BSS_CHANGED_BEACON_INT)) {
3417 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3418 bss_conf->beacon_int);
3419
Eliad Peller6a899792011-10-05 11:55:58 +02003420 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003421 }
3422
3423 if ((changed & BSS_CHANGED_BEACON)) {
3424 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003425 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426 int ieoffset = offsetof(struct ieee80211_mgmt,
3427 u.beacon.variable);
3428 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3429 u16 tmpl_id;
3430
3431 if (!beacon)
3432 goto out;
3433
3434 wl1271_debug(DEBUG_MASTER, "beacon updated");
3435
Eliad Peller1fe9f162011-10-05 11:55:48 +02003436 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 if (ret < 0) {
3438 dev_kfree_skb(beacon);
3439 goto out;
3440 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003441 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3443 CMD_TEMPL_BEACON;
3444 ret = wl1271_cmd_template_set(wl, tmpl_id,
3445 beacon->data,
3446 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003447 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 if (ret < 0) {
3449 dev_kfree_skb(beacon);
3450 goto out;
3451 }
3452
Eliad Pellerd48055d2011-09-15 12:07:04 +03003453 /* remove TIM ie from probe response */
3454 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3455
Eliad Peller26b4bf22011-09-15 12:07:05 +03003456 /*
3457 * remove p2p ie from probe response.
3458 * the fw reponds to probe requests that don't include
3459 * the p2p ie. probe requests with p2p ie will be passed,
3460 * and will be responded by the supplicant (the spec
3461 * forbids including the p2p ie when responding to probe
3462 * requests that didn't include it).
3463 */
3464 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3465 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3466
Arik Nemtsove78a2872010-10-16 19:07:21 +02003467 hdr = (struct ieee80211_hdr *) beacon->data;
3468 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3469 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003470 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003471 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003472 beacon->data,
3473 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003474 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003475 else
3476 ret = wl1271_cmd_template_set(wl,
3477 CMD_TEMPL_PROBE_RESPONSE,
3478 beacon->data,
3479 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003480 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003481 dev_kfree_skb(beacon);
3482 if (ret < 0)
3483 goto out;
3484 }
3485
3486out:
3487 return ret;
3488}
3489
3490/* AP mode changes */
3491static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003492 struct ieee80211_vif *vif,
3493 struct ieee80211_bss_conf *bss_conf,
3494 u32 changed)
3495{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003496 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003497 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Arik Nemtsove78a2872010-10-16 19:07:21 +02003499 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3500 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003501
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003503 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003504 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003505 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003506
Eliad Peller87fbcb02011-10-05 11:55:41 +02003507 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003508 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003509 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003511 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003512
Eliad Peller784f6942011-10-05 11:55:39 +02003513 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003514 if (ret < 0)
3515 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003516 }
3517
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3519 if (ret < 0)
3520 goto out;
3521
3522 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3523 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003524 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003525 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 if (ret < 0)
3527 goto out;
3528
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003529 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003530 if (ret < 0)
3531 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003532
Eliad Peller53d40d02011-10-10 10:13:02 +02003533 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003534 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 }
3536 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003537 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003538 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 if (ret < 0)
3540 goto out;
3541
Eliad Peller53d40d02011-10-10 10:13:02 +02003542 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 wl1271_debug(DEBUG_AP, "stopped AP");
3544 }
3545 }
3546 }
3547
Eliad Peller0603d892011-10-05 11:55:51 +02003548 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003549 if (ret < 0)
3550 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003551
3552 /* Handle HT information change */
3553 if ((changed & BSS_CHANGED_HT) &&
3554 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003555 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003556 bss_conf->ht_operation_mode);
3557 if (ret < 0) {
3558 wl1271_warning("Set ht information failed %d", ret);
3559 goto out;
3560 }
3561 }
3562
Arik Nemtsove78a2872010-10-16 19:07:21 +02003563out:
3564 return;
3565}
3566
3567/* STA/IBSS mode changes */
3568static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3569 struct ieee80211_vif *vif,
3570 struct ieee80211_bss_conf *bss_conf,
3571 u32 changed)
3572{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003573 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003574 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003575 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003576 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003577 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003578 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003579 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003580 bool sta_exists = false;
3581 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582
3583 if (is_ibss) {
3584 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3585 changed);
3586 if (ret < 0)
3587 goto out;
3588 }
3589
Eliad Peller227e81e2011-08-14 13:17:26 +03003590 if (changed & BSS_CHANGED_IBSS) {
3591 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003592 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003593 ibss_joined = true;
3594 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003595 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3596 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003597 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003598 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003599 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003600 }
3601 }
3602 }
3603
3604 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003605 do_join = true;
3606
3607 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003608 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 do_join = true;
3610
Eliad Peller227e81e2011-08-14 13:17:26 +03003611 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003612 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3613 bss_conf->enable_beacon ? "enabled" : "disabled");
3614
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003615 do_join = true;
3616 }
3617
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003619 bool enable = false;
3620 if (bss_conf->cqm_rssi_thold)
3621 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003622 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003623 bss_conf->cqm_rssi_thold,
3624 bss_conf->cqm_rssi_hyst);
3625 if (ret < 0)
3626 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003627 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003628 }
3629
Eliad Pellercdf09492011-10-05 11:55:44 +02003630 if (changed & BSS_CHANGED_BSSID)
3631 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003632 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003633 if (ret < 0)
3634 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003635
Eliad Peller784f6942011-10-05 11:55:39 +02003636 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003637 if (ret < 0)
3638 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003639
Eliad Pellerfa287b82010-12-26 09:27:50 +01003640 /* Need to update the BSSID (for filtering etc) */
3641 do_join = true;
3642 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003643
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003644 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3645 rcu_read_lock();
3646 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3647 if (!sta)
3648 goto sta_not_found;
3649
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003650 /* save the supp_rates of the ap */
3651 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3652 if (sta->ht_cap.ht_supported)
3653 sta_rate_set |=
3654 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003655 sta_ht_cap = sta->ht_cap;
3656 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003657
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003658sta_not_found:
3659 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003660 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003661
Arik Nemtsove78a2872010-10-16 19:07:21 +02003662 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003663 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003664 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003665 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003666 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003667 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003668
Eliad Peller74ec8392011-10-05 11:56:02 +02003669 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003670
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003671 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003672 * use basic rates from AP, and determine lowest rate
3673 * to use with control frames.
3674 */
3675 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003676 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003677 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003678 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003679 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003680 wl1271_tx_min_rate_get(wl,
3681 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003682 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003683 wlvif->rate_set =
3684 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003685 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003686 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003687 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003688 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003689 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003690
3691 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003692 * with wl1271, we don't need to update the
3693 * beacon_int and dtim_period, because the firmware
3694 * updates it by itself when the first beacon is
3695 * received after a join.
3696 */
Eliad Peller6840e372011-10-05 11:55:50 +02003697 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003698 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003699 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003700
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003701 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003702 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003703 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003704 dev_kfree_skb(wlvif->probereq);
3705 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003706 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003707 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003708 ieoffset = offsetof(struct ieee80211_mgmt,
3709 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003710 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003711
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003712 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003713 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003714 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003715 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003716 } else {
3717 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003718 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003719 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3720 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003721 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003722 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3723 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003724 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003725
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003726 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003727 dev_kfree_skb(wlvif->probereq);
3728 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003729
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003730 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003731 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003732
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003733 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003734 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003735 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003736 wl1271_tx_min_rate_get(wl,
3737 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003738 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003739 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003740 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003741
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003742 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003743 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003744
3745 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003746 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003747 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003748 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003749
3750 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003751 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003752 u32 conf_flags = wl->hw->conf.flags;
3753 /*
3754 * we might have to disable roc, if there was
3755 * no IF_OPER_UP notification.
3756 */
3757 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003758 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003759 if (ret < 0)
3760 goto out;
3761 }
3762 /*
3763 * (we also need to disable roc in case of
3764 * roaming on the same channel. until we will
3765 * have a better flow...)
3766 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003767 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3768 ret = wl12xx_croc(wl,
3769 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003770 if (ret < 0)
3771 goto out;
3772 }
3773
Eliad Peller0603d892011-10-05 11:55:51 +02003774 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003775 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003776 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003777 wl12xx_roc(wl, wlvif,
3778 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003779 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003780 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003781 }
3782 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003783
Eliad Pellerd192d262011-05-24 14:33:08 +03003784 if (changed & BSS_CHANGED_IBSS) {
3785 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3786 bss_conf->ibss_joined);
3787
3788 if (bss_conf->ibss_joined) {
3789 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003790 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003791 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003792 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003793 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003794 wl1271_tx_min_rate_get(wl,
3795 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003796
Shahar Levi06b660e2011-09-05 13:54:36 +03003797 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003798 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3799 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003800 if (ret < 0)
3801 goto out;
3802 }
3803 }
3804
Eliad Peller0603d892011-10-05 11:55:51 +02003805 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003806 if (ret < 0)
3807 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003808
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003809 if (changed & BSS_CHANGED_ARP_FILTER) {
3810 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003811 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003812
Eliad Pellerc5312772010-12-09 11:31:27 +02003813 if (bss_conf->arp_addr_cnt == 1 &&
3814 bss_conf->arp_filter_enabled) {
3815 /*
3816 * The template should have been configured only upon
3817 * association. however, it seems that the correct ip
3818 * isn't being set (when sending), so we have to
3819 * reconfigure the template upon every ip change.
3820 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003821 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003822 if (ret < 0) {
3823 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003824 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003825 }
3826
Eliad Peller0603d892011-10-05 11:55:51 +02003827 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003828 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 addr);
3830 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003831 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003832
3833 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003834 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003835 }
3836
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003837 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003838 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003839 if (ret < 0) {
3840 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003841 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003842 }
Eliad Peller251c1772011-08-14 13:17:17 +03003843
3844 /* ROC until connected (after EAPOL exchange) */
3845 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003846 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003847 if (ret < 0)
3848 goto out;
3849
Eliad Pellerba8447f2011-10-10 10:13:00 +02003850 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003851 ieee80211_get_operstate(vif));
3852 }
3853 /*
3854 * stop device role if started (we might already be in
3855 * STA role). TODO: make it better.
3856 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003857 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3858 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003859 if (ret < 0)
3860 goto out;
3861
Eliad Peller7edebf52011-10-05 11:55:52 +02003862 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003863 if (ret < 0)
3864 goto out;
3865 }
Eliad Peller05dba352011-08-23 16:37:01 +03003866
3867 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003868 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3869 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003870 enum wl1271_cmd_ps_mode mode;
3871
3872 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003873 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003874 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003875 true);
3876 if (ret < 0)
3877 goto out;
3878 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003879 }
3880
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003881 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003882 if (sta_exists) {
3883 if ((changed & BSS_CHANGED_HT) &&
3884 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003885 ret = wl1271_acx_set_ht_capabilities(wl,
3886 &sta_ht_cap,
3887 true,
Eliad Peller154da672011-10-05 11:55:53 +02003888 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003889 if (ret < 0) {
3890 wl1271_warning("Set ht cap true failed %d",
3891 ret);
3892 goto out;
3893 }
3894 }
3895 /* handle new association without HT and disassociation */
3896 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003897 ret = wl1271_acx_set_ht_capabilities(wl,
3898 &sta_ht_cap,
3899 false,
Eliad Peller154da672011-10-05 11:55:53 +02003900 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003901 if (ret < 0) {
3902 wl1271_warning("Set ht cap false failed %d",
3903 ret);
3904 goto out;
3905 }
3906 }
3907 }
3908
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003909 /* Handle HT information change. Done after join. */
3910 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003911 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003912 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003913 bss_conf->ht_operation_mode);
3914 if (ret < 0) {
3915 wl1271_warning("Set ht information failed %d", ret);
3916 goto out;
3917 }
3918 }
3919
Arik Nemtsove78a2872010-10-16 19:07:21 +02003920out:
3921 return;
3922}
3923
3924static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3925 struct ieee80211_vif *vif,
3926 struct ieee80211_bss_conf *bss_conf,
3927 u32 changed)
3928{
3929 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003930 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3931 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003932 int ret;
3933
3934 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3935 (int)changed);
3936
3937 mutex_lock(&wl->mutex);
3938
3939 if (unlikely(wl->state == WL1271_STATE_OFF))
3940 goto out;
3941
Eliad Peller10c8cd02011-10-10 10:13:06 +02003942 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3943 goto out;
3944
Ido Yariva6208652011-03-01 15:14:41 +02003945 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003946 if (ret < 0)
3947 goto out;
3948
3949 if (is_ap)
3950 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3951 else
3952 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003954 wl1271_ps_elp_sleep(wl);
3955
3956out:
3957 mutex_unlock(&wl->mutex);
3958}
3959
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003960static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3961 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003962 const struct ieee80211_tx_queue_params *params)
3963{
3964 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003965 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003966 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003967 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003968
3969 mutex_lock(&wl->mutex);
3970
3971 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3972
Kalle Valo4695dc92010-03-18 12:26:38 +02003973 if (params->uapsd)
3974 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3975 else
3976 ps_scheme = CONF_PS_SCHEME_LEGACY;
3977
Arik Nemtsov488fc542010-10-16 20:33:45 +02003978 if (wl->state == WL1271_STATE_OFF) {
3979 /*
3980 * If the state is off, the parameters will be recorded and
3981 * configured on init. This happens in AP-mode.
3982 */
3983 struct conf_tx_ac_category *conf_ac =
3984 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3985 struct conf_tx_tid *conf_tid =
3986 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3987
3988 conf_ac->ac = wl1271_tx_get_queue(queue);
3989 conf_ac->cw_min = (u8)params->cw_min;
3990 conf_ac->cw_max = params->cw_max;
3991 conf_ac->aifsn = params->aifs;
3992 conf_ac->tx_op_limit = params->txop << 5;
3993
3994 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3995 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3996 conf_tid->tsid = wl1271_tx_get_queue(queue);
3997 conf_tid->ps_scheme = ps_scheme;
3998 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3999 conf_tid->apsd_conf[0] = 0;
4000 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004001 goto out;
4002 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004003
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004004 ret = wl1271_ps_elp_wakeup(wl);
4005 if (ret < 0)
4006 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004007
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004008 /*
4009 * the txop is confed in units of 32us by the mac80211,
4010 * we need us
4011 */
Eliad Peller0603d892011-10-05 11:55:51 +02004012 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004013 params->cw_min, params->cw_max,
4014 params->aifs, params->txop << 5);
4015 if (ret < 0)
4016 goto out_sleep;
4017
Eliad Peller0603d892011-10-05 11:55:51 +02004018 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004019 CONF_CHANNEL_TYPE_EDCF,
4020 wl1271_tx_get_queue(queue),
4021 ps_scheme, CONF_ACK_POLICY_LEGACY,
4022 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004023
4024out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004025 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004026
4027out:
4028 mutex_unlock(&wl->mutex);
4029
4030 return ret;
4031}
4032
Eliad Peller37a41b42011-09-21 14:06:11 +03004033static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4034 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004035{
4036
4037 struct wl1271 *wl = hw->priv;
4038 u64 mactime = ULLONG_MAX;
4039 int ret;
4040
4041 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4042
4043 mutex_lock(&wl->mutex);
4044
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004045 if (unlikely(wl->state == WL1271_STATE_OFF))
4046 goto out;
4047
Ido Yariva6208652011-03-01 15:14:41 +02004048 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004049 if (ret < 0)
4050 goto out;
4051
4052 ret = wl1271_acx_tsf_info(wl, &mactime);
4053 if (ret < 0)
4054 goto out_sleep;
4055
4056out_sleep:
4057 wl1271_ps_elp_sleep(wl);
4058
4059out:
4060 mutex_unlock(&wl->mutex);
4061 return mactime;
4062}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004063
John W. Linvilleece550d2010-07-28 16:41:06 -04004064static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4065 struct survey_info *survey)
4066{
4067 struct wl1271 *wl = hw->priv;
4068 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004069
John W. Linvilleece550d2010-07-28 16:41:06 -04004070 if (idx != 0)
4071 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004072
John W. Linvilleece550d2010-07-28 16:41:06 -04004073 survey->channel = conf->channel;
4074 survey->filled = SURVEY_INFO_NOISE_DBM;
4075 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004076
John W. Linvilleece550d2010-07-28 16:41:06 -04004077 return 0;
4078}
4079
Arik Nemtsov409622e2011-02-23 00:22:29 +02004080static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004081 struct wl12xx_vif *wlvif,
4082 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083{
4084 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004086
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004087
4088 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004089 wl1271_warning("could not allocate HLID - too much stations");
4090 return -EBUSY;
4091 }
4092
4093 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004094 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4095 if (ret < 0) {
4096 wl1271_warning("could not allocate HLID - too many links");
4097 return -EBUSY;
4098 }
4099
4100 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004101 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004102 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004103 return 0;
4104}
4105
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004106void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004107{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004108 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004109 return;
4110
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004111 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004112 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004113 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004114 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004115 __clear_bit(hlid, &wl->ap_ps_map);
4116 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004118 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119}
4120
4121static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4122 struct ieee80211_vif *vif,
4123 struct ieee80211_sta *sta)
4124{
4125 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004126 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004127 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128 int ret = 0;
4129 u8 hlid;
4130
4131 mutex_lock(&wl->mutex);
4132
4133 if (unlikely(wl->state == WL1271_STATE_OFF))
4134 goto out;
4135
Eliad Peller536129c2011-10-05 11:55:45 +02004136 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004137 goto out;
4138
4139 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4140
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004141 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004142 if (ret < 0)
4143 goto out;
4144
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004145 wl_sta = (struct wl1271_station *)sta->drv_priv;
4146 hlid = wl_sta->hlid;
4147
Ido Yariva6208652011-03-01 15:14:41 +02004148 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004150 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151
Eliad Peller1b92f152011-10-10 10:13:09 +02004152 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004153 if (ret < 0)
4154 goto out_sleep;
4155
Eliad Pellerb67476e2011-08-14 13:17:23 +03004156 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4157 if (ret < 0)
4158 goto out_sleep;
4159
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004160 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4161 if (ret < 0)
4162 goto out_sleep;
4163
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004164out_sleep:
4165 wl1271_ps_elp_sleep(wl);
4166
Arik Nemtsov409622e2011-02-23 00:22:29 +02004167out_free_sta:
4168 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004169 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004170
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004171out:
4172 mutex_unlock(&wl->mutex);
4173 return ret;
4174}
4175
4176static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4177 struct ieee80211_vif *vif,
4178 struct ieee80211_sta *sta)
4179{
4180 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004181 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004182 struct wl1271_station *wl_sta;
4183 int ret = 0, id;
4184
4185 mutex_lock(&wl->mutex);
4186
4187 if (unlikely(wl->state == WL1271_STATE_OFF))
4188 goto out;
4189
Eliad Peller536129c2011-10-05 11:55:45 +02004190 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004191 goto out;
4192
4193 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4194
4195 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004196 id = wl_sta->hlid;
4197 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004198 goto out;
4199
Ido Yariva6208652011-03-01 15:14:41 +02004200 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004201 if (ret < 0)
4202 goto out;
4203
Eliad Pellerc690ec82011-08-14 13:17:07 +03004204 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004205 if (ret < 0)
4206 goto out_sleep;
4207
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004208 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004209
4210out_sleep:
4211 wl1271_ps_elp_sleep(wl);
4212
4213out:
4214 mutex_unlock(&wl->mutex);
4215 return ret;
4216}
4217
Luciano Coelho4623ec72011-03-21 19:26:41 +02004218static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4219 struct ieee80211_vif *vif,
4220 enum ieee80211_ampdu_mlme_action action,
4221 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4222 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004223{
4224 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004225 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004226 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004227 u8 hlid, *ba_bitmap;
4228
4229 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4230 tid);
4231
4232 /* sanity check - the fields in FW are only 8bits wide */
4233 if (WARN_ON(tid > 0xFF))
4234 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235
4236 mutex_lock(&wl->mutex);
4237
4238 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4239 ret = -EAGAIN;
4240 goto out;
4241 }
4242
Eliad Peller536129c2011-10-05 11:55:45 +02004243 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004244 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004245 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004246 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004247 struct wl1271_station *wl_sta;
4248
4249 wl_sta = (struct wl1271_station *)sta->drv_priv;
4250 hlid = wl_sta->hlid;
4251 ba_bitmap = &wl->links[hlid].ba_bitmap;
4252 } else {
4253 ret = -EINVAL;
4254 goto out;
4255 }
4256
Ido Yariva6208652011-03-01 15:14:41 +02004257 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004258 if (ret < 0)
4259 goto out;
4260
Shahar Levi70559a02011-05-22 16:10:22 +03004261 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4262 tid, action);
4263
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004264 switch (action) {
4265 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004266 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004267 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004268 break;
4269 }
4270
4271 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4272 ret = -EBUSY;
4273 wl1271_error("exceeded max RX BA sessions");
4274 break;
4275 }
4276
4277 if (*ba_bitmap & BIT(tid)) {
4278 ret = -EINVAL;
4279 wl1271_error("cannot enable RX BA session on active "
4280 "tid: %d", tid);
4281 break;
4282 }
4283
4284 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4285 hlid);
4286 if (!ret) {
4287 *ba_bitmap |= BIT(tid);
4288 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004289 }
4290 break;
4291
4292 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004293 if (!(*ba_bitmap & BIT(tid))) {
4294 ret = -EINVAL;
4295 wl1271_error("no active RX BA session on tid: %d",
4296 tid);
4297 break;
4298 }
4299
4300 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4301 hlid);
4302 if (!ret) {
4303 *ba_bitmap &= ~BIT(tid);
4304 wl->ba_rx_session_count--;
4305 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004306 break;
4307
4308 /*
4309 * The BA initiator session management in FW independently.
4310 * Falling break here on purpose for all TX APDU commands.
4311 */
4312 case IEEE80211_AMPDU_TX_START:
4313 case IEEE80211_AMPDU_TX_STOP:
4314 case IEEE80211_AMPDU_TX_OPERATIONAL:
4315 ret = -EINVAL;
4316 break;
4317
4318 default:
4319 wl1271_error("Incorrect ampdu action id=%x\n", action);
4320 ret = -EINVAL;
4321 }
4322
4323 wl1271_ps_elp_sleep(wl);
4324
4325out:
4326 mutex_unlock(&wl->mutex);
4327
4328 return ret;
4329}
4330
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004331static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4332 struct ieee80211_vif *vif,
4333 const struct cfg80211_bitrate_mask *mask)
4334{
Eliad Peller83587502011-10-10 10:12:53 +02004335 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336 struct wl1271 *wl = hw->priv;
4337 int i;
4338
4339 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4340 mask->control[NL80211_BAND_2GHZ].legacy,
4341 mask->control[NL80211_BAND_5GHZ].legacy);
4342
4343 mutex_lock(&wl->mutex);
4344
4345 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004346 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004347 wl1271_tx_enabled_rates_get(wl,
4348 mask->control[i].legacy,
4349 i);
4350 mutex_unlock(&wl->mutex);
4351
4352 return 0;
4353}
4354
Shahar Levi6d158ff2011-09-08 13:01:33 +03004355static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4356 struct ieee80211_channel_switch *ch_switch)
4357{
4358 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004359 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004360 int ret;
4361
4362 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4363
4364 mutex_lock(&wl->mutex);
4365
4366 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004367 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4368 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4369 ieee80211_chswitch_done(vif, false);
4370 }
4371 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004372 }
4373
4374 ret = wl1271_ps_elp_wakeup(wl);
4375 if (ret < 0)
4376 goto out;
4377
Eliad Peller52630c52011-10-10 10:13:08 +02004378 /* TODO: change mac80211 to pass vif as param */
4379 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4380 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004381
Eliad Peller52630c52011-10-10 10:13:08 +02004382 if (!ret)
4383 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4384 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004385
4386 wl1271_ps_elp_sleep(wl);
4387
4388out:
4389 mutex_unlock(&wl->mutex);
4390}
4391
Arik Nemtsov33437892011-04-26 23:35:39 +03004392static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4393{
4394 struct wl1271 *wl = hw->priv;
4395 bool ret = false;
4396
4397 mutex_lock(&wl->mutex);
4398
4399 if (unlikely(wl->state == WL1271_STATE_OFF))
4400 goto out;
4401
4402 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004403 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004404out:
4405 mutex_unlock(&wl->mutex);
4406
4407 return ret;
4408}
4409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410/* can't be const, mac80211 writes to this */
4411static struct ieee80211_rate wl1271_rates[] = {
4412 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004413 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4414 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004416 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4417 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004418 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4419 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4427 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004431 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4432 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004433 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004434 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4435 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004436 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004437 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4438 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004439 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004440 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4441 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004442 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004443 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4444 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004445 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004446 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4447 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004448 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004449 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4450 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451};
4452
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004453/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004454static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004455 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004456 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4458 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4459 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4462 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4463 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004464 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004465 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4466 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4467 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004468 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004469};
4470
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004471/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004472static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004473 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004474 7, /* CONF_HW_RXTX_RATE_MCS7 */
4475 6, /* CONF_HW_RXTX_RATE_MCS6 */
4476 5, /* CONF_HW_RXTX_RATE_MCS5 */
4477 4, /* CONF_HW_RXTX_RATE_MCS4 */
4478 3, /* CONF_HW_RXTX_RATE_MCS3 */
4479 2, /* CONF_HW_RXTX_RATE_MCS2 */
4480 1, /* CONF_HW_RXTX_RATE_MCS1 */
4481 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004482
4483 11, /* CONF_HW_RXTX_RATE_54 */
4484 10, /* CONF_HW_RXTX_RATE_48 */
4485 9, /* CONF_HW_RXTX_RATE_36 */
4486 8, /* CONF_HW_RXTX_RATE_24 */
4487
4488 /* TI-specific rate */
4489 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4490
4491 7, /* CONF_HW_RXTX_RATE_18 */
4492 6, /* CONF_HW_RXTX_RATE_12 */
4493 3, /* CONF_HW_RXTX_RATE_11 */
4494 5, /* CONF_HW_RXTX_RATE_9 */
4495 4, /* CONF_HW_RXTX_RATE_6 */
4496 2, /* CONF_HW_RXTX_RATE_5_5 */
4497 1, /* CONF_HW_RXTX_RATE_2 */
4498 0 /* CONF_HW_RXTX_RATE_1 */
4499};
4500
Shahar Levie8b03a22010-10-13 16:09:39 +02004501/* 11n STA capabilities */
4502#define HW_RX_HIGHEST_RATE 72
4503
Shahar Levi00d20102010-11-08 11:20:10 +00004504#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004505 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4506 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004507 .ht_supported = true, \
4508 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4509 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4510 .mcs = { \
4511 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4512 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4513 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4514 }, \
4515}
4516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004517/* can't be const, mac80211 writes to this */
4518static struct ieee80211_supported_band wl1271_band_2ghz = {
4519 .channels = wl1271_channels,
4520 .n_channels = ARRAY_SIZE(wl1271_channels),
4521 .bitrates = wl1271_rates,
4522 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004523 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004524};
4525
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004526/* 5 GHz data rates for WL1273 */
4527static struct ieee80211_rate wl1271_rates_5ghz[] = {
4528 { .bitrate = 60,
4529 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4530 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4531 { .bitrate = 90,
4532 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4533 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4534 { .bitrate = 120,
4535 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4536 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4537 { .bitrate = 180,
4538 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4539 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4540 { .bitrate = 240,
4541 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4542 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4543 { .bitrate = 360,
4544 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4545 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4546 { .bitrate = 480,
4547 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4548 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4549 { .bitrate = 540,
4550 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4551 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4552};
4553
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004554/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004555static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004556 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4557 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4558 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4559 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4560 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4561 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4562 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4563 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4564 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4565 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4566 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4567 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4568 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4569 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4570 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4571 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4572 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4573 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4574 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4575 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4576 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4577 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4578 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4579 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4580 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4581 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4582 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4583 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4584 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4585 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4586 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4587 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4588 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4589 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004590};
4591
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004592/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004593static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004594 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004595 7, /* CONF_HW_RXTX_RATE_MCS7 */
4596 6, /* CONF_HW_RXTX_RATE_MCS6 */
4597 5, /* CONF_HW_RXTX_RATE_MCS5 */
4598 4, /* CONF_HW_RXTX_RATE_MCS4 */
4599 3, /* CONF_HW_RXTX_RATE_MCS3 */
4600 2, /* CONF_HW_RXTX_RATE_MCS2 */
4601 1, /* CONF_HW_RXTX_RATE_MCS1 */
4602 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004603
4604 7, /* CONF_HW_RXTX_RATE_54 */
4605 6, /* CONF_HW_RXTX_RATE_48 */
4606 5, /* CONF_HW_RXTX_RATE_36 */
4607 4, /* CONF_HW_RXTX_RATE_24 */
4608
4609 /* TI-specific rate */
4610 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4611
4612 3, /* CONF_HW_RXTX_RATE_18 */
4613 2, /* CONF_HW_RXTX_RATE_12 */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4615 1, /* CONF_HW_RXTX_RATE_9 */
4616 0, /* CONF_HW_RXTX_RATE_6 */
4617 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4619 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4620};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004621
4622static struct ieee80211_supported_band wl1271_band_5ghz = {
4623 .channels = wl1271_channels_5ghz,
4624 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4625 .bitrates = wl1271_rates_5ghz,
4626 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004627 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004628};
4629
Tobias Klausera0ea9492010-05-20 10:38:11 +02004630static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004631 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4632 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4633};
4634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004635static const struct ieee80211_ops wl1271_ops = {
4636 .start = wl1271_op_start,
4637 .stop = wl1271_op_stop,
4638 .add_interface = wl1271_op_add_interface,
4639 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004640#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004641 .suspend = wl1271_op_suspend,
4642 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004643#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004644 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004645 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004646 .configure_filter = wl1271_op_configure_filter,
4647 .tx = wl1271_op_tx,
4648 .set_key = wl1271_op_set_key,
4649 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004650 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004651 .sched_scan_start = wl1271_op_sched_scan_start,
4652 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004653 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004654 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004655 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004656 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004657 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004658 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004659 .sta_add = wl1271_op_sta_add,
4660 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004661 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004662 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004663 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004664 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004665 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666};
4667
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004668
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004669u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004670{
4671 u8 idx;
4672
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004673 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004674
4675 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4676 wl1271_error("Illegal RX rate from HW: %d", rate);
4677 return 0;
4678 }
4679
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004680 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004681 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4682 wl1271_error("Unsupported RX rate from HW: %d", rate);
4683 return 0;
4684 }
4685
4686 return idx;
4687}
4688
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004689static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4690 struct device_attribute *attr,
4691 char *buf)
4692{
4693 struct wl1271 *wl = dev_get_drvdata(dev);
4694 ssize_t len;
4695
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004696 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004697
4698 mutex_lock(&wl->mutex);
4699 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4700 wl->sg_enabled);
4701 mutex_unlock(&wl->mutex);
4702
4703 return len;
4704
4705}
4706
4707static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4708 struct device_attribute *attr,
4709 const char *buf, size_t count)
4710{
4711 struct wl1271 *wl = dev_get_drvdata(dev);
4712 unsigned long res;
4713 int ret;
4714
Luciano Coelho6277ed62011-04-01 17:49:54 +03004715 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004716 if (ret < 0) {
4717 wl1271_warning("incorrect value written to bt_coex_mode");
4718 return count;
4719 }
4720
4721 mutex_lock(&wl->mutex);
4722
4723 res = !!res;
4724
4725 if (res == wl->sg_enabled)
4726 goto out;
4727
4728 wl->sg_enabled = res;
4729
4730 if (wl->state == WL1271_STATE_OFF)
4731 goto out;
4732
Ido Yariva6208652011-03-01 15:14:41 +02004733 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004734 if (ret < 0)
4735 goto out;
4736
4737 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4738 wl1271_ps_elp_sleep(wl);
4739
4740 out:
4741 mutex_unlock(&wl->mutex);
4742 return count;
4743}
4744
4745static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4746 wl1271_sysfs_show_bt_coex_state,
4747 wl1271_sysfs_store_bt_coex_state);
4748
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004749static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4750 struct device_attribute *attr,
4751 char *buf)
4752{
4753 struct wl1271 *wl = dev_get_drvdata(dev);
4754 ssize_t len;
4755
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004756 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004757
4758 mutex_lock(&wl->mutex);
4759 if (wl->hw_pg_ver >= 0)
4760 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4761 else
4762 len = snprintf(buf, len, "n/a\n");
4763 mutex_unlock(&wl->mutex);
4764
4765 return len;
4766}
4767
Gery Kahn6f07b722011-07-18 14:21:49 +03004768static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004769 wl1271_sysfs_show_hw_pg_ver, NULL);
4770
Ido Yariv95dac04f2011-06-06 14:57:06 +03004771static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4772 struct bin_attribute *bin_attr,
4773 char *buffer, loff_t pos, size_t count)
4774{
4775 struct device *dev = container_of(kobj, struct device, kobj);
4776 struct wl1271 *wl = dev_get_drvdata(dev);
4777 ssize_t len;
4778 int ret;
4779
4780 ret = mutex_lock_interruptible(&wl->mutex);
4781 if (ret < 0)
4782 return -ERESTARTSYS;
4783
4784 /* Let only one thread read the log at a time, blocking others */
4785 while (wl->fwlog_size == 0) {
4786 DEFINE_WAIT(wait);
4787
4788 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4789 &wait,
4790 TASK_INTERRUPTIBLE);
4791
4792 if (wl->fwlog_size != 0) {
4793 finish_wait(&wl->fwlog_waitq, &wait);
4794 break;
4795 }
4796
4797 mutex_unlock(&wl->mutex);
4798
4799 schedule();
4800 finish_wait(&wl->fwlog_waitq, &wait);
4801
4802 if (signal_pending(current))
4803 return -ERESTARTSYS;
4804
4805 ret = mutex_lock_interruptible(&wl->mutex);
4806 if (ret < 0)
4807 return -ERESTARTSYS;
4808 }
4809
4810 /* Check if the fwlog is still valid */
4811 if (wl->fwlog_size < 0) {
4812 mutex_unlock(&wl->mutex);
4813 return 0;
4814 }
4815
4816 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4817 len = min(count, (size_t)wl->fwlog_size);
4818 wl->fwlog_size -= len;
4819 memcpy(buffer, wl->fwlog, len);
4820
4821 /* Make room for new messages */
4822 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4823
4824 mutex_unlock(&wl->mutex);
4825
4826 return len;
4827}
4828
4829static struct bin_attribute fwlog_attr = {
4830 .attr = {.name = "fwlog", .mode = S_IRUSR},
4831 .read = wl1271_sysfs_read_fwlog,
4832};
4833
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004834static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004835{
4836 int ret;
4837
4838 if (wl->mac80211_registered)
4839 return 0;
4840
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004841 ret = wl1271_fetch_nvs(wl);
4842 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004843 /* NOTE: The wl->nvs->nvs element must be first, in
4844 * order to simplify the casting, we assume it is at
4845 * the beginning of the wl->nvs structure.
4846 */
4847 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004848
4849 wl->mac_addr[0] = nvs_ptr[11];
4850 wl->mac_addr[1] = nvs_ptr[10];
4851 wl->mac_addr[2] = nvs_ptr[6];
4852 wl->mac_addr[3] = nvs_ptr[5];
4853 wl->mac_addr[4] = nvs_ptr[4];
4854 wl->mac_addr[5] = nvs_ptr[3];
4855 }
4856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004857 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4858
4859 ret = ieee80211_register_hw(wl->hw);
4860 if (ret < 0) {
4861 wl1271_error("unable to register mac80211 hw: %d", ret);
4862 return ret;
4863 }
4864
4865 wl->mac80211_registered = true;
4866
Eliad Pellerd60080a2010-11-24 12:53:16 +02004867 wl1271_debugfs_init(wl);
4868
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004869 register_netdevice_notifier(&wl1271_dev_notifier);
4870
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004871 wl1271_notice("loaded");
4872
4873 return 0;
4874}
4875
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004876static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004877{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004878 if (wl->state == WL1271_STATE_PLT)
4879 __wl1271_plt_stop(wl);
4880
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004881 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004882 ieee80211_unregister_hw(wl->hw);
4883 wl->mac80211_registered = false;
4884
4885}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004886
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004887static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004888{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004889 static const u32 cipher_suites[] = {
4890 WLAN_CIPHER_SUITE_WEP40,
4891 WLAN_CIPHER_SUITE_WEP104,
4892 WLAN_CIPHER_SUITE_TKIP,
4893 WLAN_CIPHER_SUITE_CCMP,
4894 WL1271_CIPHER_SUITE_GEM,
4895 };
4896
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004897 /* The tx descriptor buffer and the TKIP space. */
4898 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4899 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004900
4901 /* unit us */
4902 /* FIXME: find a proper value */
4903 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004904 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004905
4906 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004907 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004908 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004909 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004910 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004911 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004912 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004913 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004914 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004915 IEEE80211_HW_AP_LINK_PS |
4916 IEEE80211_HW_AMPDU_AGGREGATION |
4917 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004918
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004919 wl->hw->wiphy->cipher_suites = cipher_suites;
4920 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4921
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004922 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004923 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4924 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004925 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004926 wl->hw->wiphy->max_sched_scan_ssids = 16;
4927 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004928 /*
4929 * Maximum length of elements in scanning probe request templates
4930 * should be the maximum length possible for a template, without
4931 * the IEEE80211 header of the template
4932 */
Eliad Peller154037d2011-08-14 13:17:12 +03004933 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004934 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004935
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004936 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4937 sizeof(struct ieee80211_header);
4938
Eliad Peller1ec23f72011-08-25 14:26:54 +03004939 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4940
Luciano Coelho4a31c112011-03-21 23:16:14 +02004941 /* make sure all our channels fit in the scanned_ch bitmask */
4942 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4943 ARRAY_SIZE(wl1271_channels_5ghz) >
4944 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004945 /*
4946 * We keep local copies of the band structs because we need to
4947 * modify them on a per-device basis.
4948 */
4949 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4950 sizeof(wl1271_band_2ghz));
4951 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4952 sizeof(wl1271_band_5ghz));
4953
4954 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4955 &wl->bands[IEEE80211_BAND_2GHZ];
4956 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4957 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004958
Kalle Valo12bd8942010-03-18 12:26:33 +02004959 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004960 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004961
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004962 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4963
Felipe Balbia390e852011-10-06 10:07:44 +03004964 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004965
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004966 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004967 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004968
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004969 wl->hw->max_rx_aggregation_subframes = 8;
4970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004971 return 0;
4972}
4973
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004975
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004976static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004977{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978 struct ieee80211_hw *hw;
4979 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004980 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004981 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004983 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004984
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004985 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4986 if (!hw) {
4987 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004988 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004989 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990 }
4991
4992 wl = hw->priv;
4993 memset(wl, 0, sizeof(*wl));
4994
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004995 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004996 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004998 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005000 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005001 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005002 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5003
Ido Yariva6208652011-03-01 15:14:41 +02005004 skb_queue_head_init(&wl->deferred_rx_queue);
5005 skb_queue_head_init(&wl->deferred_tx_queue);
5006
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005007 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005008 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005009 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5010 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5011 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005012
Eliad Peller92ef8962011-06-07 12:50:46 +03005013 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5014 if (!wl->freezable_wq) {
5015 ret = -ENOMEM;
5016 goto err_hw;
5017 }
5018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005019 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005020 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005022 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005023 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005024 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005025 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005026 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005027 wl->ap_ps_map = 0;
5028 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005029 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005030 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005031 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005032 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005033 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005034 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005035 wl->fwlog_size = 0;
5036 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005037
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005038 /* The system link is always allocated */
5039 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5040
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005041 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005042 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005043 wl->tx_frames[i] = NULL;
5044
5045 spin_lock_init(&wl->wl_lock);
5046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 wl->state = WL1271_STATE_OFF;
5048 mutex_init(&wl->mutex);
5049
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005050 /* Apply default driver configuration. */
5051 wl1271_conf_init(wl);
5052
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005053 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5054 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5055 if (!wl->aggr_buf) {
5056 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005057 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005058 }
5059
Ido Yariv990f5de2011-03-31 10:06:59 +02005060 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5061 if (!wl->dummy_packet) {
5062 ret = -ENOMEM;
5063 goto err_aggr;
5064 }
5065
Ido Yariv95dac04f2011-06-06 14:57:06 +03005066 /* Allocate one page for the FW log */
5067 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5068 if (!wl->fwlog) {
5069 ret = -ENOMEM;
5070 goto err_dummy_packet;
5071 }
5072
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005073 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005074
Ido Yariv990f5de2011-03-31 10:06:59 +02005075err_dummy_packet:
5076 dev_kfree_skb(wl->dummy_packet);
5077
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005078err_aggr:
5079 free_pages((unsigned long)wl->aggr_buf, order);
5080
Eliad Peller92ef8962011-06-07 12:50:46 +03005081err_wq:
5082 destroy_workqueue(wl->freezable_wq);
5083
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005084err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005085 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005086 ieee80211_free_hw(hw);
5087
5088err_hw_alloc:
5089
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005090 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005091}
5092
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005093static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005094{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005095 /* Unblock any fwlog readers */
5096 mutex_lock(&wl->mutex);
5097 wl->fwlog_size = -1;
5098 wake_up_interruptible_all(&wl->fwlog_waitq);
5099 mutex_unlock(&wl->mutex);
5100
Felipe Balbif79f8902011-10-06 13:05:25 +03005101 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005102
Felipe Balbif79f8902011-10-06 13:05:25 +03005103 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005106 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005107 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005108 free_pages((unsigned long)wl->aggr_buf,
5109 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005110
5111 wl1271_debugfs_exit(wl);
5112
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005113 vfree(wl->fw);
5114 wl->fw = NULL;
5115 kfree(wl->nvs);
5116 wl->nvs = NULL;
5117
5118 kfree(wl->fw_status);
5119 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005120 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005121
5122 ieee80211_free_hw(wl->hw);
5123
5124 return 0;
5125}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005126
Felipe Balbia390e852011-10-06 10:07:44 +03005127static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5128{
5129 struct wl1271 *wl = cookie;
5130 unsigned long flags;
5131
5132 wl1271_debug(DEBUG_IRQ, "IRQ");
5133
5134 /* complete the ELP completion */
5135 spin_lock_irqsave(&wl->wl_lock, flags);
5136 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5137 if (wl->elp_compl) {
5138 complete(wl->elp_compl);
5139 wl->elp_compl = NULL;
5140 }
5141
5142 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5143 /* don't enqueue a work right now. mark it as pending */
5144 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5145 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5146 disable_irq_nosync(wl->irq);
5147 pm_wakeup_event(wl->dev, 0);
5148 spin_unlock_irqrestore(&wl->wl_lock, flags);
5149 return IRQ_HANDLED;
5150 }
5151 spin_unlock_irqrestore(&wl->wl_lock, flags);
5152
5153 return IRQ_WAKE_THREAD;
5154}
5155
Felipe Balbice2a2172011-10-05 14:12:55 +03005156static int __devinit wl12xx_probe(struct platform_device *pdev)
5157{
Felipe Balbia390e852011-10-06 10:07:44 +03005158 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5159 struct ieee80211_hw *hw;
5160 struct wl1271 *wl;
5161 unsigned long irqflags;
5162 int ret = -ENODEV;
5163
5164 hw = wl1271_alloc_hw();
5165 if (IS_ERR(hw)) {
5166 wl1271_error("can't allocate hw");
5167 ret = PTR_ERR(hw);
5168 goto out;
5169 }
5170
5171 wl = hw->priv;
5172 wl->irq = platform_get_irq(pdev, 0);
5173 wl->ref_clock = pdata->board_ref_clock;
5174 wl->tcxo_clock = pdata->board_tcxo_clock;
5175 wl->platform_quirks = pdata->platform_quirks;
5176 wl->set_power = pdata->set_power;
5177 wl->dev = &pdev->dev;
5178 wl->if_ops = pdata->ops;
5179
5180 platform_set_drvdata(pdev, wl);
5181
5182 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5183 irqflags = IRQF_TRIGGER_RISING;
5184 else
5185 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5186
5187 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5188 irqflags,
5189 pdev->name, wl);
5190 if (ret < 0) {
5191 wl1271_error("request_irq() failed: %d", ret);
5192 goto out_free_hw;
5193 }
5194
5195 ret = enable_irq_wake(wl->irq);
5196 if (!ret) {
5197 wl->irq_wake_enabled = true;
5198 device_init_wakeup(wl->dev, 1);
5199 if (pdata->pwr_in_suspend)
5200 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5201
5202 }
5203 disable_irq(wl->irq);
5204
5205 ret = wl1271_init_ieee80211(wl);
5206 if (ret)
5207 goto out_irq;
5208
5209 ret = wl1271_register_hw(wl);
5210 if (ret)
5211 goto out_irq;
5212
Felipe Balbif79f8902011-10-06 13:05:25 +03005213 /* Create sysfs file to control bt coex state */
5214 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5215 if (ret < 0) {
5216 wl1271_error("failed to create sysfs file bt_coex_state");
5217 goto out_irq;
5218 }
5219
5220 /* Create sysfs file to get HW PG version */
5221 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5222 if (ret < 0) {
5223 wl1271_error("failed to create sysfs file hw_pg_ver");
5224 goto out_bt_coex_state;
5225 }
5226
5227 /* Create sysfs file for the FW log */
5228 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5229 if (ret < 0) {
5230 wl1271_error("failed to create sysfs file fwlog");
5231 goto out_hw_pg_ver;
5232 }
5233
Felipe Balbice2a2172011-10-05 14:12:55 +03005234 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005235
Felipe Balbif79f8902011-10-06 13:05:25 +03005236out_hw_pg_ver:
5237 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5238
5239out_bt_coex_state:
5240 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5241
Felipe Balbia390e852011-10-06 10:07:44 +03005242out_irq:
5243 free_irq(wl->irq, wl);
5244
5245out_free_hw:
5246 wl1271_free_hw(wl);
5247
5248out:
5249 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005250}
5251
5252static int __devexit wl12xx_remove(struct platform_device *pdev)
5253{
Felipe Balbia390e852011-10-06 10:07:44 +03005254 struct wl1271 *wl = platform_get_drvdata(pdev);
5255
5256 if (wl->irq_wake_enabled) {
5257 device_init_wakeup(wl->dev, 0);
5258 disable_irq_wake(wl->irq);
5259 }
5260 wl1271_unregister_hw(wl);
5261 free_irq(wl->irq, wl);
5262 wl1271_free_hw(wl);
5263
Felipe Balbice2a2172011-10-05 14:12:55 +03005264 return 0;
5265}
5266
5267static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
5268 { "wl12xx-sdio", 0 },
5269 { "wl12xx-spi", 0 },
5270 { } /* Terminating Entry */
5271};
5272MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5273
5274static struct platform_driver wl12xx_driver = {
5275 .probe = wl12xx_probe,
5276 .remove = __devexit_p(wl12xx_remove),
5277 .id_table = wl12xx_id_table,
5278 .driver = {
5279 .name = "wl12xx",
5280 .owner = THIS_MODULE,
5281 }
5282};
5283
5284static int __init wl12xx_init(void)
5285{
5286 return platform_driver_register(&wl12xx_driver);
5287}
5288module_init(wl12xx_init);
5289
5290static void __exit wl12xx_exit(void)
5291{
5292 platform_driver_unregister(&wl12xx_driver);
5293}
5294module_exit(wl12xx_exit);
5295
Guy Eilam491bbd62011-01-12 10:33:29 +01005296u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005297EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005298module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005299MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5300
Ido Yariv95dac04f2011-06-06 14:57:06 +03005301module_param_named(fwlog, fwlog_param, charp, 0);
5302MODULE_PARM_DESC(keymap,
5303 "FW logger options: continuous, ondemand, dbgpins or disable");
5304
Eliad Peller2a5bff02011-08-25 18:10:59 +03005305module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5306MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5307
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005308MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005309MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005310MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");