blob: 1cf987785053d518863ce4984f6ddf5f1cb14735 [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-Cohen958b20e02011-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 Peller536129c82011-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
386
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200387static void wl1271_device_release(struct device *dev)
388{
389
390}
391
392static struct platform_device wl1271_device = {
393 .name = "wl1271",
394 .id = -1,
395
396 /* device model insists to have a release function */
397 .dev = {
398 .release = wl1271_device_release,
399 },
400};
401
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200402static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300403static LIST_HEAD(wl_list);
404
Eliad Pellerba8447f62011-10-10 10:13:00 +0200405static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
406 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407{
408 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200409
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300410 if (operstate != IF_OPER_UP)
411 return 0;
412
Eliad Peller8181aec2011-10-10 10:13:04 +0200413 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300414 return 0;
415
Eliad Peller154da672011-10-05 11:55:53 +0200416 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300417 if (ret < 0)
418 return ret;
419
Eliad Peller0603d892011-10-05 11:55:51 +0200420 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300421
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300422 wl1271_info("Association completed.");
423 return 0;
424}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300425static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
426 void *arg)
427{
428 struct net_device *dev = arg;
429 struct wireless_dev *wdev;
430 struct wiphy *wiphy;
431 struct ieee80211_hw *hw;
432 struct wl1271 *wl;
433 struct wl1271 *wl_temp;
Eliad Pellerba8447f62011-10-10 10:13:00 +0200434 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300435 int ret = 0;
436
437 /* Check that this notification is for us. */
438 if (what != NETDEV_CHANGE)
439 return NOTIFY_DONE;
440
441 wdev = dev->ieee80211_ptr;
442 if (wdev == NULL)
443 return NOTIFY_DONE;
444
445 wiphy = wdev->wiphy;
446 if (wiphy == NULL)
447 return NOTIFY_DONE;
448
449 hw = wiphy_priv(wiphy);
450 if (hw == NULL)
451 return NOTIFY_DONE;
452
453 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200454 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300455 list_for_each_entry(wl, &wl_list, list) {
456 if (wl == wl_temp)
457 break;
458 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200459 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300460 if (wl != wl_temp)
461 return NOTIFY_DONE;
462
463 mutex_lock(&wl->mutex);
464
465 if (wl->state == WL1271_STATE_OFF)
466 goto out;
467
Eliad Pellerba8447f62011-10-10 10:13:00 +0200468 wl12xx_for_each_wlvif_sta(wl, wlvif) {
469 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
470 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300471
Eliad Pellerba8447f62011-10-10 10:13:00 +0200472 ret = wl1271_ps_elp_wakeup(wl);
473 if (ret < 0)
474 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475
Eliad Pellerba8447f62011-10-10 10:13:00 +0200476 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477
Eliad Pellerba8447f62011-10-10 10:13:00 +0200478 wl1271_ps_elp_sleep(wl);
479 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300480out:
481 mutex_unlock(&wl->mutex);
482
483 return NOTIFY_OK;
484}
485
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100486static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200487 struct regulatory_request *request)
488{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100489 struct ieee80211_supported_band *band;
490 struct ieee80211_channel *ch;
491 int i;
492
493 band = wiphy->bands[IEEE80211_BAND_5GHZ];
494 for (i = 0; i < band->n_channels; i++) {
495 ch = &band->channels[i];
496 if (ch->flags & IEEE80211_CHAN_DISABLED)
497 continue;
498
499 if (ch->flags & IEEE80211_CHAN_RADAR)
500 ch->flags |= IEEE80211_CHAN_NO_IBSS |
501 IEEE80211_CHAN_PASSIVE_SCAN;
502
503 }
504
505 return 0;
506}
507
Eliad Peller9eb599e2011-10-10 10:12:59 +0200508static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
509 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510{
511 int ret = 0;
512
513 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200514 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 if (ret < 0)
516 goto out;
517
518 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200519 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300520 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522out:
523 return ret;
524}
525
526/*
527 * this function is being called when the rx_streaming interval
528 * has beed changed or rx_streaming should be disabled
529 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200530int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300531{
532 int ret = 0;
533 int period = wl->conf.rx_streaming.interval;
534
535 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200536 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 goto out;
538
539 /* reconfigure/disable according to new streaming_period */
540 if (period &&
Eliad Pellerba8447f62011-10-10 10:13:00 +0200541 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 (wl->conf.rx_streaming.always ||
543 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200544 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200546 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300547 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200548 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300549 }
550out:
551 return ret;
552}
553
554static void wl1271_rx_streaming_enable_work(struct work_struct *work)
555{
556 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200557 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
558 rx_streaming_enable_work);
559 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560
561 mutex_lock(&wl->mutex);
562
Eliad Peller0744bdb2011-10-10 10:13:05 +0200563 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f62011-10-10 10:13:00 +0200564 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300565 (!wl->conf.rx_streaming.always &&
566 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
567 goto out;
568
569 if (!wl->conf.rx_streaming.interval)
570 goto out;
571
572 ret = wl1271_ps_elp_wakeup(wl);
573 if (ret < 0)
574 goto out;
575
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 if (ret < 0)
578 goto out_sleep;
579
580 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200581 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300582 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
583
584out_sleep:
585 wl1271_ps_elp_sleep(wl);
586out:
587 mutex_unlock(&wl->mutex);
588}
589
590static void wl1271_rx_streaming_disable_work(struct work_struct *work)
591{
592 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200593 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
594 rx_streaming_disable_work);
595 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300596
597 mutex_lock(&wl->mutex);
598
Eliad Peller0744bdb2011-10-10 10:13:05 +0200599 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300600 goto out;
601
602 ret = wl1271_ps_elp_wakeup(wl);
603 if (ret < 0)
604 goto out;
605
Eliad Peller9eb599e2011-10-10 10:12:59 +0200606 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300607 if (ret)
608 goto out_sleep;
609
610out_sleep:
611 wl1271_ps_elp_sleep(wl);
612out:
613 mutex_unlock(&wl->mutex);
614}
615
616static void wl1271_rx_streaming_timer(unsigned long data)
617{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200618 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
619 struct wl1271 *wl = wlvif->wl;
620 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300621}
622
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623static void wl1271_conf_init(struct wl1271 *wl)
624{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300625
626 /*
627 * This function applies the default configuration to the driver. This
628 * function is invoked upon driver load (spi probe.)
629 *
630 * The configuration is stored in a run-time structure in order to
631 * facilitate for run-time adjustment of any of the parameters. Making
632 * changes to the configuration structure will apply the new values on
633 * the next interface up (wl1271_op_start.)
634 */
635
636 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300637 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300638
Ido Yariv95dac04f2011-06-06 14:57:06 +0300639 /* Adjust settings according to optional module parameters */
640 if (fwlog_param) {
641 if (!strcmp(fwlog_param, "continuous")) {
642 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
643 } else if (!strcmp(fwlog_param, "ondemand")) {
644 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
645 } else if (!strcmp(fwlog_param, "dbgpins")) {
646 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
647 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
648 } else if (!strcmp(fwlog_param, "disable")) {
649 wl->conf.fwlog.mem_blocks = 0;
650 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
651 } else {
652 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
653 }
654 }
655}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657static int wl1271_plt_init(struct wl1271 *wl)
658{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200659 struct conf_tx_ac_category *conf_ac;
660 struct conf_tx_tid *conf_tid;
661 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_general_parms(wl);
665 else
666 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id == CHIP_ID_1283_PG20)
671 ret = wl128x_cmd_radio_parms(wl);
672 else
673 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200674 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200675 return ret;
676
Shahar Levi49d750ca2011-03-06 16:32:09 +0200677 if (wl->chip.id != CHIP_ID_1283_PG20) {
678 ret = wl1271_cmd_ext_radio_parms(wl);
679 if (ret < 0)
680 return ret;
681 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200682 if (ret < 0)
683 return ret;
684
Shahar Levi48a61472011-03-06 16:32:08 +0200685 /* Chip-specific initializations */
686 ret = wl1271_chip_specific_init(wl);
687 if (ret < 0)
688 return ret;
689
Eliad Peller92c77c72011-10-05 11:55:40 +0200690 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 if (ret < 0)
692 return ret;
693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 ret = wl1271_acx_init_mem_config(wl);
695 if (ret < 0)
696 return ret;
697
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 /* PHY layer config */
699 ret = wl1271_init_phy_config(wl);
700 if (ret < 0)
701 goto out_free_memmap;
702
703 ret = wl1271_acx_dco_itrim_params(wl);
704 if (ret < 0)
705 goto out_free_memmap;
706
707 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200708 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200709 if (ret < 0)
710 goto out_free_memmap;
711
712 /* Bluetooth WLAN coexistence */
713 ret = wl1271_init_pta(wl);
714 if (ret < 0)
715 goto out_free_memmap;
716
Shahar Leviff868432011-04-11 15:41:46 +0300717 /* FM WLAN coexistence */
718 ret = wl1271_acx_fm_coex(wl);
719 if (ret < 0)
720 goto out_free_memmap;
721
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 /* Energy detection */
723 ret = wl1271_init_energy_detection(wl);
724 if (ret < 0)
725 goto out_free_memmap;
726
Eliad Peller7f0979882011-08-14 13:17:06 +0300727 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600728 if (ret < 0)
729 goto out_free_memmap;
730
Luciano Coelho12419cc2010-02-18 13:25:44 +0200731 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100732 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200733 if (ret < 0)
734 goto out_free_memmap;
735
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200736 /* Default TID/AC configuration */
737 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200738 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200739 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200740 /* TODO: fix */
741 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200742 conf_ac->cw_max, conf_ac->aifsn,
743 conf_ac->tx_op_limit);
744 if (ret < 0)
745 goto out_free_memmap;
746
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200748 /* TODO: fix */
749 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 conf_tid->channel_type,
751 conf_tid->tsid,
752 conf_tid->ps_scheme,
753 conf_tid->ack_policy,
754 conf_tid->apsd_conf[0],
755 conf_tid->apsd_conf[1]);
756 if (ret < 0)
757 goto out_free_memmap;
758 }
759
Luciano Coelho12419cc2010-02-18 13:25:44 +0200760 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200761 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763 goto out_free_memmap;
764
765 /* Configure for CAM power saving (ie. always active) */
766 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
767 if (ret < 0)
768 goto out_free_memmap;
769
770 /* configure PM */
771 ret = wl1271_acx_pm_config(wl);
772 if (ret < 0)
773 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774
775 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200776
777 out_free_memmap:
778 kfree(wl->target_mem_map);
779 wl->target_mem_map = NULL;
780
781 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782}
783
Eliad Peller6e8cd332011-10-10 10:13:13 +0200784static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
785 struct wl12xx_vif *wlvif,
786 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787{
Arik Nemtsovda032092011-08-25 12:43:15 +0300788 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200789
Arik Nemtsovb622d992011-02-23 00:22:31 +0200790 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300791 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200792
793 /*
794 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300795 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200796 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300797 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200798 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200799
Arik Nemtsovda032092011-08-25 12:43:15 +0300800 /*
801 * Start high-level PS if the STA is asleep with enough blocks in FW.
802 * Make an exception if this is the only connected station. In this
803 * case FW-memory congestion is not a problem.
804 */
805 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200806 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200807}
808
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300809static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200810 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300811 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200813 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200814 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300815 u8 hlid, cnt;
816
817 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200818
819 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
820 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
821 wl1271_debug(DEBUG_PSM,
822 "link ps prev 0x%x cur 0x%x changed 0x%x",
823 wl->ap_fw_ps_map, cur_fw_ps_map,
824 wl->ap_fw_ps_map ^ cur_fw_ps_map);
825
826 wl->ap_fw_ps_map = cur_fw_ps_map;
827 }
828
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200829 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
830 lnk = &wl->links[hlid];
831 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200832
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200833 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
834 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200835
Eliad Peller6e8cd332011-10-10 10:13:13 +0200836 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
837 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200838 }
839}
840
Eliad Peller4d56ad92011-08-14 13:17:05 +0300841static void wl12xx_fw_status(struct wl1271 *wl,
842 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200844 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200845 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200846 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300847 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300848 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849
Eliad Peller4d56ad92011-08-14 13:17:05 +0300850 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300852 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
853 "drv_rx_counter = %d, tx_results_counter = %d)",
854 status->intr,
855 status->fw_rx_counter,
856 status->drv_rx_counter,
857 status->tx_results_counter);
858
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300859 for (i = 0; i < NUM_TX_QUEUES; i++) {
860 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300861 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300862 (status->tx_released_pkts[i] -
863 wl->tx_pkts_freed[i]) & 0xff;
864
865 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
866 }
867
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300868 /* prevent wrap-around in total blocks counter */
869 if (likely(wl->tx_blocks_freed <=
870 le32_to_cpu(status->total_released_blks)))
871 freed_blocks = le32_to_cpu(status->total_released_blks) -
872 wl->tx_blocks_freed;
873 else
874 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
875 le32_to_cpu(status->total_released_blks);
876
Eliad Peller4d56ad92011-08-14 13:17:05 +0300877 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200878
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300879 wl->tx_allocated_blocks -= freed_blocks;
880
Eliad Peller4d56ad92011-08-14 13:17:05 +0300881 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 /*
884 * The FW might change the total number of TX memblocks before
885 * we get a notification about blocks being released. Thus, the
886 * available blocks calculation might yield a temporary result
887 * which is lower than the actual available blocks. Keeping in
888 * mind that only blocks that were allocated can be moved from
889 * TX to RX, tx_blocks_available should never decrease here.
890 */
891 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
892 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893
Ido Yariva5225502010-10-12 14:49:10 +0200894 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200895 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200896 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897
Eliad Peller4d56ad92011-08-14 13:17:05 +0300898 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200899 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200900 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200901 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200904 getnstimeofday(&ts);
905 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
906 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907}
908
Ido Yariva6208652011-03-01 15:14:41 +0200909static void wl1271_flush_deferred_work(struct wl1271 *wl)
910{
911 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200912
Ido Yariva6208652011-03-01 15:14:41 +0200913 /* Pass all received frames to the network stack */
914 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
915 ieee80211_rx_ni(wl->hw, skb);
916
917 /* Return sent skbs to the network stack */
918 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300919 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200920}
921
922static void wl1271_netstack_work(struct work_struct *work)
923{
924 struct wl1271 *wl =
925 container_of(work, struct wl1271, netstack_work);
926
927 do {
928 wl1271_flush_deferred_work(wl);
929 } while (skb_queue_len(&wl->deferred_rx_queue));
930}
931
932#define WL1271_IRQ_MAX_LOOPS 256
933
934irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300937 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200938 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200939 struct wl1271 *wl = (struct wl1271 *)cookie;
940 bool done = false;
941 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200942 unsigned long flags;
943
944 /* TX might be handled here, avoid redundant work */
945 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
946 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947
Ido Yariv341b7cd2011-03-31 10:07:01 +0200948 /*
949 * In case edge triggered interrupt must be used, we cannot iterate
950 * more than once without introducing race conditions with the hardirq.
951 */
952 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
953 loopcount = 1;
954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955 mutex_lock(&wl->mutex);
956
957 wl1271_debug(DEBUG_IRQ, "IRQ work");
958
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 goto out;
961
Ido Yariva6208652011-03-01 15:14:41 +0200962 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 if (ret < 0)
964 goto out;
965
Ido Yariva6208652011-03-01 15:14:41 +0200966 while (!done && loopcount--) {
967 /*
968 * In order to avoid a race with the hardirq, clear the flag
969 * before acknowledging the chip. Since the mutex is held,
970 * wl1271_ps_elp_wakeup cannot be called concurrently.
971 */
972 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
973 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200974
Eliad Peller4d56ad92011-08-14 13:17:05 +0300975 wl12xx_fw_status(wl, wl->fw_status);
976 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200977 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200979 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200980 continue;
981 }
982
Eliad Pellerccc83b02010-10-27 14:09:57 +0200983 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
984 wl1271_error("watchdog interrupt received! "
985 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300986 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200987
988 /* restarting the chip. ignore any other interrupt. */
989 goto out;
990 }
991
Ido Yariva6208652011-03-01 15:14:41 +0200992 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200993 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
994
Eliad Peller4d56ad92011-08-14 13:17:05 +0300995 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200996
Ido Yariva5225502010-10-12 14:49:10 +0200997 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200998 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200999 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001000 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001001 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001002 /*
1003 * In order to avoid starvation of the TX path,
1004 * call the work function directly.
1005 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001006 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001007 } else {
1008 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001009 }
1010
Ido Yariv8aad2462011-03-01 15:14:38 +02001011 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001012 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001013 (wl->tx_results_count & 0xff))
1014 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001015
1016 /* Make sure the deferred queues don't get too long */
1017 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1018 skb_queue_len(&wl->deferred_rx_queue);
1019 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1020 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001021 }
1022
1023 if (intr & WL1271_ACX_INTR_EVENT_A) {
1024 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1025 wl1271_event_handle(wl, 0);
1026 }
1027
1028 if (intr & WL1271_ACX_INTR_EVENT_B) {
1029 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1030 wl1271_event_handle(wl, 1);
1031 }
1032
1033 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1034 wl1271_debug(DEBUG_IRQ,
1035 "WL1271_ACX_INTR_INIT_COMPLETE");
1036
1037 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1038 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 }
1040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 wl1271_ps_elp_sleep(wl);
1042
1043out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001044 spin_lock_irqsave(&wl->wl_lock, flags);
1045 /* In case TX was not handled here, queue TX work */
1046 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1047 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001048 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001049 ieee80211_queue_work(wl->hw, &wl->tx_work);
1050 spin_unlock_irqrestore(&wl->wl_lock, flags);
1051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001053
1054 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055}
Ido Yariva6208652011-03-01 15:14:41 +02001056EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058static int wl1271_fetch_firmware(struct wl1271 *wl)
1059{
1060 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001061 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 int ret;
1063
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001064 if (wl->chip.id == CHIP_ID_1283_PG20)
1065 fw_name = WL128X_FW_NAME;
1066 else
1067 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001068
1069 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1070
Felipe Balbia390e852011-10-06 10:07:44 +03001071 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 if (ret < 0) {
1074 wl1271_error("could not get firmware: %d", ret);
1075 return ret;
1076 }
1077
1078 if (fw->size % 4) {
1079 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1080 fw->size);
1081 ret = -EILSEQ;
1082 goto out;
1083 }
1084
Arik Nemtsov166d5042010-10-16 21:44:57 +02001085 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001087 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088
1089 if (!wl->fw) {
1090 wl1271_error("could not allocate memory for the firmware");
1091 ret = -ENOMEM;
1092 goto out;
1093 }
1094
1095 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 ret = 0;
1097
1098out:
1099 release_firmware(fw);
1100
1101 return ret;
1102}
1103
1104static int wl1271_fetch_nvs(struct wl1271 *wl)
1105{
1106 const struct firmware *fw;
1107 int ret;
1108
Felipe Balbia390e852011-10-06 10:07:44 +03001109 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
1111 if (ret < 0) {
1112 wl1271_error("could not get nvs file: %d", ret);
1113 return ret;
1114 }
1115
Shahar Levibc765bf2011-03-06 16:32:10 +02001116 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001117
1118 if (!wl->nvs) {
1119 wl1271_error("could not allocate memory for the nvs file");
1120 ret = -ENOMEM;
1121 goto out;
1122 }
1123
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001124 wl->nvs_len = fw->size;
1125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126out:
1127 release_firmware(fw);
1128
1129 return ret;
1130}
1131
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001132void wl12xx_queue_recovery_work(struct wl1271 *wl)
1133{
1134 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1135 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1136}
1137
Ido Yariv95dac04f2011-06-06 14:57:06 +03001138size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1139{
1140 size_t len = 0;
1141
1142 /* The FW log is a length-value list, find where the log end */
1143 while (len < maxlen) {
1144 if (memblock[len] == 0)
1145 break;
1146 if (len + memblock[len] + 1 > maxlen)
1147 break;
1148 len += memblock[len] + 1;
1149 }
1150
1151 /* Make sure we have enough room */
1152 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1153
1154 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1155 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1156 wl->fwlog_size += len;
1157
1158 return len;
1159}
1160
1161static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1162{
1163 u32 addr;
1164 u32 first_addr;
1165 u8 *block;
1166
1167 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1168 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1169 (wl->conf.fwlog.mem_blocks == 0))
1170 return;
1171
1172 wl1271_info("Reading FW panic log");
1173
1174 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1175 if (!block)
1176 return;
1177
1178 /*
1179 * Make sure the chip is awake and the logger isn't active.
1180 * This might fail if the firmware hanged.
1181 */
1182 if (!wl1271_ps_elp_wakeup(wl))
1183 wl12xx_cmd_stop_fwlog(wl);
1184
1185 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001186 wl12xx_fw_status(wl, wl->fw_status);
1187 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001188 if (!first_addr)
1189 goto out;
1190
1191 /* Traverse the memory blocks linked list */
1192 addr = first_addr;
1193 do {
1194 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1195 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1196 false);
1197
1198 /*
1199 * Memory blocks are linked to one another. The first 4 bytes
1200 * of each memory block hold the hardware address of the next
1201 * one. The last memory block points to the first one.
1202 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001203 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001204 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1205 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1206 break;
1207 } while (addr && (addr != first_addr));
1208
1209 wake_up_interruptible(&wl->fwlog_waitq);
1210
1211out:
1212 kfree(block);
1213}
1214
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001215static void wl1271_recovery_work(struct work_struct *work)
1216{
1217 struct wl1271 *wl =
1218 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001219 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001220 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001221
1222 mutex_lock(&wl->mutex);
1223
1224 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001225 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001226
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001227 /* Avoid a recursive recovery */
1228 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1229
Ido Yariv95dac04f2011-06-06 14:57:06 +03001230 wl12xx_read_fwlog_panic(wl);
1231
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001232 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1233 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001234
Eliad Peller2a5bff02011-08-25 18:10:59 +03001235 BUG_ON(bug_on_recovery);
1236
Oz Krakowskib992c682011-06-26 10:36:02 +03001237 /*
1238 * Advance security sequence number to overcome potential progress
1239 * in the firmware during recovery. This doens't hurt if the network is
1240 * not encrypted.
1241 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001242 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f62011-10-10 10:13:00 +02001243 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001244 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001245 wlvif->tx_security_seq +=
1246 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1247 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001248
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001249 /* Prevent spurious TX during FW restart */
1250 ieee80211_stop_queues(wl->hw);
1251
Luciano Coelho33c2c062011-05-10 14:46:02 +03001252 if (wl->sched_scanning) {
1253 ieee80211_sched_scan_stopped(wl->hw);
1254 wl->sched_scanning = false;
1255 }
1256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001257 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001258 while (!list_empty(&wl->wlvif_list)) {
1259 wlvif = list_first_entry(&wl->wlvif_list,
1260 struct wl12xx_vif, list);
1261 vif = wl12xx_wlvif_to_vif(wlvif);
1262 __wl1271_op_remove_interface(wl, vif, false);
1263 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001264 mutex_unlock(&wl->mutex);
1265 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001266
1267 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1268
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001269 ieee80211_restart_hw(wl->hw);
1270
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001271 /*
1272 * Its safe to enable TX now - the queues are stopped after a request
1273 * to restart the HW.
1274 */
1275 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001276 return;
1277out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001278 mutex_unlock(&wl->mutex);
1279}
1280
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281static void wl1271_fw_wakeup(struct wl1271 *wl)
1282{
1283 u32 elp_reg;
1284
1285 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001286 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287}
1288
1289static int wl1271_setup(struct wl1271 *wl)
1290{
1291 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1292 if (!wl->fw_status)
1293 return -ENOMEM;
1294
1295 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1296 if (!wl->tx_res_if) {
1297 kfree(wl->fw_status);
1298 return -ENOMEM;
1299 }
1300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 return 0;
1302}
1303
1304static int wl1271_chip_wakeup(struct wl1271 *wl)
1305{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001306 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307 int ret = 0;
1308
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001309 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001310 ret = wl1271_power_on(wl);
1311 if (ret < 0)
1312 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001314 wl1271_io_reset(wl);
1315 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
1317 /* We don't need a real memory partition here, because we only want
1318 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001319 memset(&partition, 0, sizeof(partition));
1320 partition.reg.start = REGISTERS_BASE;
1321 partition.reg.size = REGISTERS_DOWN_SIZE;
1322 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
1324 /* ELP module wake up */
1325 wl1271_fw_wakeup(wl);
1326
1327 /* whal_FwCtrl_BootSm() */
1328
1329 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001330 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331
1332 /* 1. check if chip id is valid */
1333
1334 switch (wl->chip.id) {
1335 case CHIP_ID_1271_PG10:
1336 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1337 wl->chip.id);
1338
1339 ret = wl1271_setup(wl);
1340 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 break;
1343 case CHIP_ID_1271_PG20:
1344 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1345 wl->chip.id);
1346
1347 ret = wl1271_setup(wl);
1348 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001349 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001351 case CHIP_ID_1283_PG20:
1352 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1353 wl->chip.id);
1354
1355 ret = wl1271_setup(wl);
1356 if (ret < 0)
1357 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001358
Ido Yariv0da13da2011-03-31 10:06:58 +02001359 if (wl1271_set_block_size(wl))
1360 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001361 break;
1362 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001364 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 }
1368
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001369 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 ret = wl1271_fetch_firmware(wl);
1371 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001372 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 }
1374
1375 /* No NVS from netlink, try to get it from the filesystem */
1376 if (wl->nvs == NULL) {
1377 ret = wl1271_fetch_nvs(wl);
1378 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001379 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 }
1381
1382out:
1383 return ret;
1384}
1385
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001386int wl1271_plt_start(struct wl1271 *wl)
1387{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001388 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001389 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390 int ret;
1391
1392 mutex_lock(&wl->mutex);
1393
1394 wl1271_notice("power up");
1395
1396 if (wl->state != WL1271_STATE_OFF) {
1397 wl1271_error("cannot go into PLT state because not "
1398 "in off state: %d", wl->state);
1399 ret = -EBUSY;
1400 goto out;
1401 }
1402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 while (retries) {
1404 retries--;
1405 ret = wl1271_chip_wakeup(wl);
1406 if (ret < 0)
1407 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001409 ret = wl1271_boot(wl);
1410 if (ret < 0)
1411 goto power_off;
1412
1413 ret = wl1271_plt_init(wl);
1414 if (ret < 0)
1415 goto irq_disable;
1416
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001417 wl->state = WL1271_STATE_PLT;
1418 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001419 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001420
Gery Kahn6f07b722011-07-18 14:21:49 +03001421 /* update hw/fw version info in wiphy struct */
1422 wiphy->hw_version = wl->chip.id;
1423 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1424 sizeof(wiphy->fw_version));
1425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426 goto out;
1427
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001428irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001429 mutex_unlock(&wl->mutex);
1430 /* Unlocking the mutex in the middle of handling is
1431 inherently unsafe. In this case we deem it safe to do,
1432 because we need to let any possibly pending IRQ out of
1433 the system (and while we are WL1271_STATE_OFF the IRQ
1434 work function will not do anything.) Also, any other
1435 possible concurrent operations will fail due to the
1436 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001437 wl1271_disable_interrupts(wl);
1438 wl1271_flush_deferred_work(wl);
1439 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001440 mutex_lock(&wl->mutex);
1441power_off:
1442 wl1271_power_off(wl);
1443 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001445 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1446 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447out:
1448 mutex_unlock(&wl->mutex);
1449
1450 return ret;
1451}
1452
Luciano Coelho4623ec72011-03-21 19:26:41 +02001453static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454{
1455 int ret = 0;
1456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 wl1271_notice("power down");
1458
1459 if (wl->state != WL1271_STATE_PLT) {
1460 wl1271_error("cannot power down because not in PLT "
1461 "state: %d", wl->state);
1462 ret = -EBUSY;
1463 goto out;
1464 }
1465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 wl1271_power_off(wl);
1467
1468 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001469 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001471 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001472 wl1271_disable_interrupts(wl);
1473 wl1271_flush_deferred_work(wl);
1474 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001475 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001476 mutex_lock(&wl->mutex);
1477out:
1478 return ret;
1479}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001480
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001481int wl1271_plt_stop(struct wl1271 *wl)
1482{
1483 int ret;
1484
1485 mutex_lock(&wl->mutex);
1486 ret = __wl1271_plt_stop(wl);
1487 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488 return ret;
1489}
1490
Johannes Berg7bb45682011-02-24 14:42:06 +01001491static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492{
1493 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001494 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1495 struct ieee80211_vif *vif = info->control.vif;
1496 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001497 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001498 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001499 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001501 mapping = skb_get_queue_mapping(skb);
1502 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001503
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001504 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001505
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001506 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001507
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001508 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001509 if (hlid == WL12XX_INVALID_LINK_ID ||
1510 !test_bit(hlid, wlvif->links_map)) {
1511 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1512 dev_kfree_skb(skb);
1513 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001514 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001516 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1517 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1518
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001519 wl->tx_queue_count[q]++;
1520
1521 /*
1522 * The workqueue is slow to process the tx_queue and we need stop
1523 * the queue here, otherwise the queue will get too long.
1524 */
1525 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1526 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1527 ieee80211_stop_queue(wl->hw, mapping);
1528 set_bit(q, &wl->stopped_queues_map);
1529 }
1530
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 /*
1532 * The chip specific setup must run before the first TX packet -
1533 * before that, the tx_work will not be initialized!
1534 */
1535
Ido Yarivb07d4032011-03-01 15:14:43 +02001536 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1537 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001538 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001539
Arik Nemtsov04216da2011-08-14 13:17:38 +03001540out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001541 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542}
1543
Shahar Leviae47c452011-03-06 16:32:14 +02001544int wl1271_tx_dummy_packet(struct wl1271 *wl)
1545{
Ido Yariv990f5de2011-03-31 10:06:59 +02001546 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001547 int q;
1548
1549 /* no need to queue a new dummy packet if one is already pending */
1550 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1551 return 0;
1552
1553 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001554
Ido Yariv990f5de2011-03-31 10:06:59 +02001555 spin_lock_irqsave(&wl->wl_lock, flags);
1556 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001557 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001558 spin_unlock_irqrestore(&wl->wl_lock, flags);
1559
1560 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1561 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001562 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001563
1564 /*
1565 * If the FW TX is busy, TX work will be scheduled by the threaded
1566 * interrupt handler function
1567 */
1568 return 0;
1569}
1570
1571/*
1572 * The size of the dummy packet should be at least 1400 bytes. However, in
1573 * order to minimize the number of bus transactions, aligning it to 512 bytes
1574 * boundaries could be beneficial, performance wise
1575 */
1576#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1577
Luciano Coelhocf27d862011-04-01 21:08:23 +03001578static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001579{
1580 struct sk_buff *skb;
1581 struct ieee80211_hdr_3addr *hdr;
1582 unsigned int dummy_packet_size;
1583
1584 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1585 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1586
1587 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001588 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001589 wl1271_warning("Failed to allocate a dummy packet skb");
1590 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001591 }
1592
1593 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1594
1595 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1596 memset(hdr, 0, sizeof(*hdr));
1597 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001598 IEEE80211_STYPE_NULLFUNC |
1599 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001600
Ido Yariv990f5de2011-03-31 10:06:59 +02001601 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001602
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001603 /* Dummy packets require the TID to be management */
1604 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001605
1606 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001607 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001608 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001609
Ido Yariv990f5de2011-03-31 10:06:59 +02001610 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001611}
1612
Ido Yariv990f5de2011-03-31 10:06:59 +02001613
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001614static struct notifier_block wl1271_dev_notifier = {
1615 .notifier_call = wl1271_dev_notify,
1616};
1617
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001618#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001619static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1620 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001621{
Eliad Pellere85d1622011-06-27 13:06:43 +03001622 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001623
Eliad Peller94390642011-05-13 11:57:13 +03001624 mutex_lock(&wl->mutex);
1625
Eliad Pellerba8447f62011-10-10 10:13:00 +02001626 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001627 goto out_unlock;
1628
Eliad Peller94390642011-05-13 11:57:13 +03001629 ret = wl1271_ps_elp_wakeup(wl);
1630 if (ret < 0)
1631 goto out_unlock;
1632
1633 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001634 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001635 DECLARE_COMPLETION_ONSTACK(compl);
1636
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001637 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001638 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001639 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001640 if (ret < 0)
1641 goto out_sleep;
1642
1643 /* we must unlock here so we will be able to get events */
1644 wl1271_ps_elp_sleep(wl);
1645 mutex_unlock(&wl->mutex);
1646
1647 ret = wait_for_completion_timeout(
1648 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1649 if (ret <= 0) {
1650 wl1271_warning("couldn't enter ps mode!");
1651 ret = -EBUSY;
1652 goto out;
1653 }
1654
1655 /* take mutex again, and wakeup */
1656 mutex_lock(&wl->mutex);
1657
1658 ret = wl1271_ps_elp_wakeup(wl);
1659 if (ret < 0)
1660 goto out_unlock;
1661 }
1662out_sleep:
1663 wl1271_ps_elp_sleep(wl);
1664out_unlock:
1665 mutex_unlock(&wl->mutex);
1666out:
1667 return ret;
1668
1669}
1670
Eliad Peller0603d892011-10-05 11:55:51 +02001671static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1672 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001673{
Eliad Pellere85d1622011-06-27 13:06:43 +03001674 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001675
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001676 mutex_lock(&wl->mutex);
1677
Eliad Peller53d40d02011-10-10 10:13:02 +02001678 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001679 goto out_unlock;
1680
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001681 ret = wl1271_ps_elp_wakeup(wl);
1682 if (ret < 0)
1683 goto out_unlock;
1684
Eliad Peller0603d892011-10-05 11:55:51 +02001685 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001686
1687 wl1271_ps_elp_sleep(wl);
1688out_unlock:
1689 mutex_unlock(&wl->mutex);
1690 return ret;
1691
1692}
1693
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001694static int wl1271_configure_suspend(struct wl1271 *wl,
1695 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001696{
Eliad Peller536129c82011-10-05 11:55:45 +02001697 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001698 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c82011-10-05 11:55:45 +02001699 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001700 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001701 return 0;
1702}
1703
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001704static void wl1271_configure_resume(struct wl1271 *wl,
1705 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001706{
1707 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02001708 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1709 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001710
1711 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001712 return;
1713
1714 mutex_lock(&wl->mutex);
1715 ret = wl1271_ps_elp_wakeup(wl);
1716 if (ret < 0)
1717 goto out;
1718
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001719 if (is_sta) {
1720 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001721 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001722 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001723 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001724 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001725 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001726 }
Eliad Peller94390642011-05-13 11:57:13 +03001727
1728 wl1271_ps_elp_sleep(wl);
1729out:
1730 mutex_unlock(&wl->mutex);
1731}
1732
Eliad Peller402e48612011-05-13 11:57:09 +03001733static int wl1271_op_suspend(struct ieee80211_hw *hw,
1734 struct cfg80211_wowlan *wow)
1735{
1736 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001737 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 int ret;
1739
Eliad Peller402e48612011-05-13 11:57:09 +03001740 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001742
Eliad Peller4a859df2011-06-06 12:21:52 +03001743 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001744 wl12xx_for_each_wlvif(wl, wlvif) {
1745 ret = wl1271_configure_suspend(wl, wlvif);
1746 if (ret < 0) {
1747 wl1271_warning("couldn't prepare device to suspend");
1748 return ret;
1749 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 /* flush any remaining work */
1752 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001753
1754 /*
1755 * disable and re-enable interrupts in order to flush
1756 * the threaded_irq
1757 */
1758 wl1271_disable_interrupts(wl);
1759
1760 /*
1761 * set suspended flag to avoid triggering a new threaded_irq
1762 * work. no need for spinlock as interrupts are disabled.
1763 */
1764 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1765
1766 wl1271_enable_interrupts(wl);
1767 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001768 wl12xx_for_each_wlvif(wl, wlvif) {
1769 flush_delayed_work(&wlvif->pspoll_work);
1770 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 flush_delayed_work(&wl->elp_work);
1772
Eliad Peller402e48612011-05-13 11:57:09 +03001773 return 0;
1774}
1775
1776static int wl1271_op_resume(struct ieee80211_hw *hw)
1777{
1778 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001779 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001780 unsigned long flags;
1781 bool run_irq_work = false;
1782
Eliad Peller402e48612011-05-13 11:57:09 +03001783 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1784 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001785 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001786
1787 /*
1788 * re-enable irq_work enqueuing, and call irq_work directly if
1789 * there is a pending work.
1790 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001791 spin_lock_irqsave(&wl->wl_lock, flags);
1792 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1793 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1794 run_irq_work = true;
1795 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001796
Eliad Peller4a859df2011-06-06 12:21:52 +03001797 if (run_irq_work) {
1798 wl1271_debug(DEBUG_MAC80211,
1799 "run postponed irq_work directly");
1800 wl1271_irq(0, wl);
1801 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001802 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001803 wl12xx_for_each_wlvif(wl, wlvif) {
1804 wl1271_configure_resume(wl, wlvif);
1805 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001806 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001807
Eliad Peller402e48612011-05-13 11:57:09 +03001808 return 0;
1809}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001810#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001811
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812static int wl1271_op_start(struct ieee80211_hw *hw)
1813{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001814 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1815
1816 /*
1817 * We have to delay the booting of the hardware because
1818 * we need to know the local MAC address before downloading and
1819 * initializing the firmware. The MAC address cannot be changed
1820 * after boot, and without the proper MAC address, the firmware
1821 * will not function properly.
1822 *
1823 * The MAC address is first known when the corresponding interface
1824 * is added. That is where we will initialize the hardware.
1825 */
1826
1827 return 0;
1828}
1829
1830static void wl1271_op_stop(struct ieee80211_hw *hw)
1831{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001832 struct wl1271 *wl = hw->priv;
1833 int i;
1834
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001835 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001836
Eliad Peller10c8cd02011-10-10 10:13:06 +02001837 mutex_lock(&wl->mutex);
1838 if (wl->state == WL1271_STATE_OFF) {
1839 mutex_unlock(&wl->mutex);
1840 return;
1841 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001842 /*
1843 * this must be before the cancel_work calls below, so that the work
1844 * functions don't perform further work.
1845 */
1846 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001847 mutex_unlock(&wl->mutex);
1848
1849 mutex_lock(&wl_list_mutex);
1850 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001851 mutex_unlock(&wl_list_mutex);
1852
1853 wl1271_disable_interrupts(wl);
1854 wl1271_flush_deferred_work(wl);
1855 cancel_delayed_work_sync(&wl->scan_complete_work);
1856 cancel_work_sync(&wl->netstack_work);
1857 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001858 cancel_delayed_work_sync(&wl->elp_work);
1859
1860 /* let's notify MAC80211 about the remaining pending TX frames */
1861 wl12xx_tx_reset(wl, true);
1862 mutex_lock(&wl->mutex);
1863
1864 wl1271_power_off(wl);
1865
1866 wl->band = IEEE80211_BAND_2GHZ;
1867
1868 wl->rx_counter = 0;
1869 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1870 wl->tx_blocks_available = 0;
1871 wl->tx_allocated_blocks = 0;
1872 wl->tx_results_count = 0;
1873 wl->tx_packets_count = 0;
1874 wl->time_offset = 0;
1875 wl->vif = NULL;
1876 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1877 wl->ap_fw_ps_map = 0;
1878 wl->ap_ps_map = 0;
1879 wl->sched_scanning = false;
1880 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1881 memset(wl->links_map, 0, sizeof(wl->links_map));
1882 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1883 wl->active_sta_count = 0;
1884
1885 /* The system link is always allocated */
1886 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1887
1888 /*
1889 * this is performed after the cancel_work calls and the associated
1890 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1891 * get executed before all these vars have been reset.
1892 */
1893 wl->flags = 0;
1894
1895 wl->tx_blocks_freed = 0;
1896
1897 for (i = 0; i < NUM_TX_QUEUES; i++) {
1898 wl->tx_pkts_freed[i] = 0;
1899 wl->tx_allocated_pkts[i] = 0;
1900 }
1901
1902 wl1271_debugfs_reset(wl);
1903
1904 kfree(wl->fw_status);
1905 wl->fw_status = NULL;
1906 kfree(wl->tx_res_if);
1907 wl->tx_res_if = NULL;
1908 kfree(wl->target_mem_map);
1909 wl->target_mem_map = NULL;
1910
1911 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001912}
1913
Eliad Pellere5a359f2011-10-10 10:13:15 +02001914static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1915{
1916 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1917 WL12XX_MAX_RATE_POLICIES);
1918 if (policy >= WL12XX_MAX_RATE_POLICIES)
1919 return -EBUSY;
1920
1921 __set_bit(policy, wl->rate_policies_map);
1922 *idx = policy;
1923 return 0;
1924}
1925
1926static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1927{
1928 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1929 return;
1930
1931 __clear_bit(*idx, wl->rate_policies_map);
1932 *idx = WL12XX_MAX_RATE_POLICIES;
1933}
1934
Eliad Peller536129c82011-10-05 11:55:45 +02001935static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001936{
Eliad Peller536129c82011-10-05 11:55:45 +02001937 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001938 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001939 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001940 return WL1271_ROLE_P2P_GO;
1941 else
1942 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001943
1944 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001945 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001946 return WL1271_ROLE_P2P_CL;
1947 else
1948 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001949
Eliad Peller227e81e2011-08-14 13:17:26 +03001950 case BSS_TYPE_IBSS:
1951 return WL1271_ROLE_IBSS;
1952
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001953 default:
Eliad Peller536129c82011-10-05 11:55:45 +02001954 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001955 }
1956 return WL12XX_INVALID_ROLE_TYPE;
1957}
1958
Eliad Peller83587502011-10-10 10:12:53 +02001959static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001960{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001961 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001962 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001963
Eliad Peller48e93e42011-10-10 10:12:58 +02001964 /* clear everything but the persistent data */
1965 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001966
1967 switch (ieee80211_vif_type_p2p(vif)) {
1968 case NL80211_IFTYPE_P2P_CLIENT:
1969 wlvif->p2p = 1;
1970 /* fall-through */
1971 case NL80211_IFTYPE_STATION:
1972 wlvif->bss_type = BSS_TYPE_STA_BSS;
1973 break;
1974 case NL80211_IFTYPE_ADHOC:
1975 wlvif->bss_type = BSS_TYPE_IBSS;
1976 break;
1977 case NL80211_IFTYPE_P2P_GO:
1978 wlvif->p2p = 1;
1979 /* fall-through */
1980 case NL80211_IFTYPE_AP:
1981 wlvif->bss_type = BSS_TYPE_AP_BSS;
1982 break;
1983 default:
1984 wlvif->bss_type = MAX_BSS_TYPE;
1985 return -EOPNOTSUPP;
1986 }
1987
Eliad Peller0603d892011-10-05 11:55:51 +02001988 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001989 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001990 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001991
Eliad Pellere936bbe2011-10-05 11:55:56 +02001992 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1993 wlvif->bss_type == BSS_TYPE_IBSS) {
1994 /* init sta/ibss data */
1995 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001996 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1997 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1998 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001999 } else {
2000 /* init ap data */
2001 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2002 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002003 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2004 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2005 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2006 wl12xx_allocate_rate_policy(wl,
2007 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002008 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002009
Eliad Peller83587502011-10-10 10:12:53 +02002010 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2011 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002012 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002013 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002014 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002015 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2016
Eliad Peller1b92f152011-10-10 10:13:09 +02002017 /*
2018 * mac80211 configures some values globally, while we treat them
2019 * per-interface. thus, on init, we have to copy them from wl
2020 */
2021 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002022 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002023 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002024
Eliad Peller9eb599e2011-10-10 10:12:59 +02002025 INIT_WORK(&wlvif->rx_streaming_enable_work,
2026 wl1271_rx_streaming_enable_work);
2027 INIT_WORK(&wlvif->rx_streaming_disable_work,
2028 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002029 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller876272142011-10-10 10:12:54 +02002030 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002031
Eliad Peller9eb599e2011-10-10 10:12:59 +02002032 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2033 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002034 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002035}
2036
Eliad Peller1d095472011-10-10 10:12:49 +02002037static bool wl12xx_init_fw(struct wl1271 *wl)
2038{
2039 int retries = WL1271_BOOT_RETRIES;
2040 bool booted = false;
2041 struct wiphy *wiphy = wl->hw->wiphy;
2042 int ret;
2043
2044 while (retries) {
2045 retries--;
2046 ret = wl1271_chip_wakeup(wl);
2047 if (ret < 0)
2048 goto power_off;
2049
2050 ret = wl1271_boot(wl);
2051 if (ret < 0)
2052 goto power_off;
2053
2054 ret = wl1271_hw_init(wl);
2055 if (ret < 0)
2056 goto irq_disable;
2057
2058 booted = true;
2059 break;
2060
2061irq_disable:
2062 mutex_unlock(&wl->mutex);
2063 /* Unlocking the mutex in the middle of handling is
2064 inherently unsafe. In this case we deem it safe to do,
2065 because we need to let any possibly pending IRQ out of
2066 the system (and while we are WL1271_STATE_OFF the IRQ
2067 work function will not do anything.) Also, any other
2068 possible concurrent operations will fail due to the
2069 current state, hence the wl1271 struct should be safe. */
2070 wl1271_disable_interrupts(wl);
2071 wl1271_flush_deferred_work(wl);
2072 cancel_work_sync(&wl->netstack_work);
2073 mutex_lock(&wl->mutex);
2074power_off:
2075 wl1271_power_off(wl);
2076 }
2077
2078 if (!booted) {
2079 wl1271_error("firmware boot failed despite %d retries",
2080 WL1271_BOOT_RETRIES);
2081 goto out;
2082 }
2083
2084 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2085
2086 /* update hw/fw version info in wiphy struct */
2087 wiphy->hw_version = wl->chip.id;
2088 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2089 sizeof(wiphy->fw_version));
2090
2091 /*
2092 * Now we know if 11a is supported (info from the NVS), so disable
2093 * 11a channels if not supported
2094 */
2095 if (!wl->enable_11a)
2096 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2097
2098 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2099 wl->enable_11a ? "" : "not ");
2100
2101 wl->state = WL1271_STATE_ON;
2102out:
2103 return booted;
2104}
2105
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002106static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2107 struct ieee80211_vif *vif)
2108{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002109 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002110 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002112 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002113 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002115 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002116 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117
2118 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002119 ret = wl1271_ps_elp_wakeup(wl);
2120 if (ret < 0)
2121 goto out_unlock;
2122
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002123 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002124 wl1271_debug(DEBUG_MAC80211,
2125 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002126 ret = -EBUSY;
2127 goto out;
2128 }
2129
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002130 /*
2131 * in some very corner case HW recovery scenarios its possible to
2132 * get here before __wl1271_op_remove_interface is complete, so
2133 * opt out if that is the case.
2134 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002135 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2136 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002137 ret = -EBUSY;
2138 goto out;
2139 }
2140
Eliad Peller83587502011-10-10 10:12:53 +02002141 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002142 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002143 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002144
Eliad Peller252efa42011-10-05 11:56:00 +02002145 wlvif->wl = wl;
Eliad Peller536129c82011-10-05 11:55:45 +02002146 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002147 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2148 ret = -EINVAL;
2149 goto out;
2150 }
Eliad Peller1d095472011-10-10 10:12:49 +02002151
Eliad Peller784f6942011-10-05 11:55:39 +02002152 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002153 * TODO: after the nvs issue will be solved, move this block
2154 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002155 */
Eliad Peller1d095472011-10-10 10:12:49 +02002156 if (wl->state == WL1271_STATE_OFF) {
2157 /*
2158 * we still need this in order to configure the fw
2159 * while uploading the nvs
2160 */
2161 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162
Eliad Peller1d095472011-10-10 10:12:49 +02002163 booted = wl12xx_init_fw(wl);
2164 if (!booted) {
2165 ret = -EINVAL;
2166 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002167 }
Eliad Peller1d095472011-10-10 10:12:49 +02002168 }
Eliad Peller04e80792011-08-14 13:17:09 +03002169
Eliad Peller1d095472011-10-10 10:12:49 +02002170 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2171 wlvif->bss_type == BSS_TYPE_IBSS) {
2172 /*
2173 * The device role is a special role used for
2174 * rx and tx frames prior to association (as
2175 * the STA role can get packets only from
2176 * its associated bssid)
2177 */
Eliad Peller784f6942011-10-05 11:55:39 +02002178 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002179 WL1271_ROLE_DEVICE,
2180 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002181 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002182 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002183 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184
Eliad Peller1d095472011-10-10 10:12:49 +02002185 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2186 role_type, &wlvif->role_id);
2187 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002188 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002189
2190 ret = wl1271_init_vif_specific(wl, vif);
2191 if (ret < 0)
2192 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002193
2194 wl->vif = vif;
Eliad Peller876272142011-10-10 10:12:54 +02002195 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002196 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002197
2198 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2199 wl->ap_count++;
2200 else
2201 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002202out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002203 wl1271_ps_elp_sleep(wl);
2204out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205 mutex_unlock(&wl->mutex);
2206
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002207 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002208 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002209 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002210 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002212 return ret;
2213}
2214
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002215static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +02002216 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002217 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218{
Eliad Peller536129c82011-10-05 11:55:45 +02002219 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002220 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002222 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223
Eliad Peller10c8cd02011-10-10 10:13:06 +02002224 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2225 return;
2226
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002227 /* because of hardware recovery, we may get here twice */
2228 if (wl->state != WL1271_STATE_ON)
2229 return;
2230
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002231 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002232
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002233 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c82011-10-05 11:55:45 +02002234 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002235 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002236
Eliad Pellerbaf62772011-10-10 10:12:52 +02002237 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2238 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002239 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002240 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002241 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002242 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002243 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002244 }
2245
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002246 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2247 /* disable active roles */
2248 ret = wl1271_ps_elp_wakeup(wl);
2249 if (ret < 0)
2250 goto deinit;
2251
Eliad Peller536129c82011-10-05 11:55:45 +02002252 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002253 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002254 if (ret < 0)
2255 goto deinit;
2256 }
2257
Eliad Peller0603d892011-10-05 11:55:51 +02002258 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002259 if (ret < 0)
2260 goto deinit;
2261
2262 wl1271_ps_elp_sleep(wl);
2263 }
2264deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002265 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002266 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002267
2268 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2269 wlvif->bss_type == BSS_TYPE_IBSS) {
2270 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2271 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2272 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2273 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2274 } else {
2275 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2276 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2277 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2278 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2279 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2280 wl12xx_free_rate_policy(wl,
2281 &wlvif->ap.ucast_rate_idx[i]);
2282 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002283
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002284 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002285 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002286 if (wl->last_wlvif == wlvif)
2287 wl->last_wlvif = NULL;
Eliad Peller876272142011-10-10 10:12:54 +02002288 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002289 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002290 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002291 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002292
Eliad Pellera4e41302011-10-11 11:49:15 +02002293 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2294 wl->ap_count--;
2295 else
2296 wl->sta_count--;
2297
Eliad Pellerbaf62772011-10-10 10:12:52 +02002298 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002299 del_timer_sync(&wlvif->rx_streaming_timer);
2300 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2301 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002302 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002303
Eliad Pellerbaf62772011-10-10 10:12:52 +02002304 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002305}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002306
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002307static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2308 struct ieee80211_vif *vif)
2309{
2310 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002311 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002312 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002313
2314 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002315
2316 if (wl->state == WL1271_STATE_OFF ||
2317 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2318 goto out;
2319
Juuso Oikarinen67353292010-11-18 15:19:02 +02002320 /*
2321 * wl->vif can be null here if someone shuts down the interface
2322 * just when hardware recovery has been started.
2323 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002324 wl12xx_for_each_wlvif(wl, iter) {
2325 if (iter != wlvif)
2326 continue;
2327
Eliad Peller536129c82011-10-05 11:55:45 +02002328 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002329 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002330 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002331 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002332out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002333 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002334 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335}
2336
Eliad Peller87fbcb02011-10-05 11:55:41 +02002337static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2338 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002339{
2340 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002341 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002342
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002343 /*
2344 * One of the side effects of the JOIN command is that is clears
2345 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2346 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002347 * Currently the only valid scenario for JOIN during association
2348 * is on roaming, in which case we will also be given new keys.
2349 * Keep the below message for now, unless it starts bothering
2350 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002351 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002352 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002353 wl1271_info("JOIN while associated.");
2354
2355 if (set_assoc)
Eliad Pellerba8447f62011-10-10 10:13:00 +02002356 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002357
Eliad Peller227e81e2011-08-14 13:17:26 +03002358 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002359 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002360 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002361 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002362 if (ret < 0)
2363 goto out;
2364
Eliad Pellerba8447f62011-10-10 10:13:00 +02002365 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 goto out;
2367
2368 /*
2369 * The join command disable the keep-alive mode, shut down its process,
2370 * and also clear the template config, so we need to reset it all after
2371 * the join. The acx_aid starts the keep-alive process, and the order
2372 * of the commands below is relevant.
2373 */
Eliad Peller0603d892011-10-05 11:55:51 +02002374 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002375 if (ret < 0)
2376 goto out;
2377
Eliad Peller0603d892011-10-05 11:55:51 +02002378 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002379 if (ret < 0)
2380 goto out;
2381
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002382 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002383 if (ret < 0)
2384 goto out;
2385
Eliad Peller0603d892011-10-05 11:55:51 +02002386 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2387 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002388 ACX_KEEP_ALIVE_TPL_VALID);
2389 if (ret < 0)
2390 goto out;
2391
2392out:
2393 return ret;
2394}
2395
Eliad Peller0603d892011-10-05 11:55:51 +02002396static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002397{
2398 int ret;
2399
Eliad Peller52630c52011-10-10 10:13:08 +02002400 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002401 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2402
Shahar Levi6d158ff2011-09-08 13:01:33 +03002403 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002404 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002405 }
2406
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002407 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002408 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002409 if (ret < 0)
2410 goto out;
2411
Oz Krakowskib992c682011-06-26 10:36:02 +03002412 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002413 wlvif->tx_security_last_seq_lsb = 0;
2414 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002415
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002416out:
2417 return ret;
2418}
2419
Eliad Peller87fbcb02011-10-05 11:55:41 +02002420static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002421{
Eliad Peller1b92f152011-10-10 10:13:09 +02002422 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002423 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002424}
2425
Eliad Peller251c1772011-08-14 13:17:17 +03002426static bool wl12xx_is_roc(struct wl1271 *wl)
2427{
2428 u8 role_id;
2429
2430 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2431 if (role_id >= WL12XX_MAX_ROLES)
2432 return false;
2433
2434 return true;
2435}
2436
Eliad Peller87fbcb02011-10-05 11:55:41 +02002437static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2438 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002439{
2440 int ret;
2441
2442 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002443 /* no need to croc if we weren't busy (e.g. during boot) */
2444 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002445 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002446 if (ret < 0)
2447 goto out;
2448
Eliad Peller7edebf52011-10-05 11:55:52 +02002449 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002450 if (ret < 0)
2451 goto out;
2452 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002453 wlvif->rate_set =
2454 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2455 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002456 if (ret < 0)
2457 goto out;
2458 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002459 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002460 ACX_KEEP_ALIVE_TPL_INVALID);
2461 if (ret < 0)
2462 goto out;
2463 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2464 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002465 /* The current firmware only supports sched_scan in idle */
2466 if (wl->sched_scanning) {
2467 wl1271_scan_sched_scan_stop(wl);
2468 ieee80211_sched_scan_stopped(wl->hw);
2469 }
2470
Eliad Peller7edebf52011-10-05 11:55:52 +02002471 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002472 if (ret < 0)
2473 goto out;
2474
Eliad Peller1b92f152011-10-10 10:13:09 +02002475 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002476 if (ret < 0)
2477 goto out;
2478 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2479 }
2480
2481out:
2482 return ret;
2483}
2484
Eliad Peller9f259c42011-10-10 10:13:12 +02002485static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2486 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002487{
Eliad Peller9f259c42011-10-10 10:13:12 +02002488 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2489 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490
2491 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2492
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002493 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002494 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002495 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002496 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002497 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002498 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002499 wlvif->band = conf->channel->band;
2500 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002501
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002502 if (!is_ap) {
2503 /*
2504 * FIXME: the mac80211 should really provide a fixed
2505 * rate to use here. for now, just use the smallest
2506 * possible rate for the band as a fixed rate for
2507 * association frames and other control messages.
2508 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002509 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002510 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002511
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002512 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002513 wl1271_tx_min_rate_get(wl,
2514 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002515 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002516 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002517 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002518 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002519
Eliad Pellerba8447f62011-10-10 10:13:00 +02002520 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2521 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002522 if (wl12xx_is_roc(wl)) {
2523 /* roaming */
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 Peller87fbcb02011-10-05 11:55:41 +02002529 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002530 if (ret < 0)
2531 wl1271_warning("cmd join on channel "
2532 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002533 } else {
2534 /*
2535 * change the ROC channel. do it only if we are
2536 * not idle. otherwise, CROC will be called
2537 * anyway.
2538 */
2539 if (wl12xx_is_roc(wl) &&
2540 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002541 ret = wl12xx_croc(wl,
2542 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002543 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002544 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002545
Eliad Peller1b92f152011-10-10 10:13:09 +02002546 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002547 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002548 if (ret < 0)
2549 wl1271_warning("roc failed %d",
2550 ret);
2551 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002552 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002553 }
2554 }
2555
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002556 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002557 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002558 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002559 if (ret < 0)
2560 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002561 }
2562
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002563 /*
2564 * if mac80211 changes the PSM mode, make sure the mode is not
2565 * incorrectly changed after the pspoll failure active window.
2566 */
2567 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002568 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002569
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002570 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002571 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2572 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002573
2574 /*
2575 * We enter PSM only if we're already associated.
2576 * If we're not, we'll enter it when joining an SSID,
2577 * through the bss_info_changed() hook.
2578 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002579 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002580 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002581 ret = wl1271_ps_set_mode(wl, wlvif,
2582 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002583 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002584 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002585 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002586 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002587 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588
Eliad Pellerc29bb002011-10-10 10:13:03 +02002589 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590
Eliad Pellerc29bb002011-10-10 10:13:03 +02002591 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002592 ret = wl1271_ps_set_mode(wl, wlvif,
2593 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002594 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002595 }
2596
Eliad Peller6bd65022011-10-10 10:13:11 +02002597 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002598 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002600 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002601
Eliad Peller6bd65022011-10-10 10:13:11 +02002602 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002603 }
2604
Eliad Peller9f259c42011-10-10 10:13:12 +02002605 return 0;
2606}
2607
2608static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2609{
2610 struct wl1271 *wl = hw->priv;
2611 struct wl12xx_vif *wlvif;
2612 struct ieee80211_conf *conf = &hw->conf;
2613 int channel, ret = 0;
2614
2615 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2616
2617 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2618 " changed 0x%x",
2619 channel,
2620 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2621 conf->power_level,
2622 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2623 changed);
2624
2625 /*
2626 * mac80211 will go to idle nearly immediately after transmitting some
2627 * frames, such as the deauth. To make sure those frames reach the air,
2628 * wait here until the TX queue is fully flushed.
2629 */
2630 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2631 (conf->flags & IEEE80211_CONF_IDLE))
2632 wl1271_tx_flush(wl);
2633
2634 mutex_lock(&wl->mutex);
2635
2636 /* we support configuring the channel and band even while off */
2637 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2638 wl->band = conf->channel->band;
2639 wl->channel = channel;
2640 }
2641
2642 if (changed & IEEE80211_CONF_CHANGE_POWER)
2643 wl->power_level = conf->power_level;
2644
2645 if (unlikely(wl->state == WL1271_STATE_OFF))
2646 goto out;
2647
2648 ret = wl1271_ps_elp_wakeup(wl);
2649 if (ret < 0)
2650 goto out;
2651
2652 /* configure each interface */
2653 wl12xx_for_each_wlvif(wl, wlvif) {
2654 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2655 if (ret < 0)
2656 goto out_sleep;
2657 }
2658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659out_sleep:
2660 wl1271_ps_elp_sleep(wl);
2661
2662out:
2663 mutex_unlock(&wl->mutex);
2664
2665 return ret;
2666}
2667
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002668struct wl1271_filter_params {
2669 bool enabled;
2670 int mc_list_length;
2671 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2672};
2673
Jiri Pirko22bedad32010-04-01 21:22:57 +00002674static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2675 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002676{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002677 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002678 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002679 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002680
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002681 if (unlikely(wl->state == WL1271_STATE_OFF))
2682 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002683
Juuso Oikarinen74441132009-10-13 12:47:53 +03002684 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002685 if (!fp) {
2686 wl1271_error("Out of memory setting filters.");
2687 return 0;
2688 }
2689
2690 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002691 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002692 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2693 fp->enabled = false;
2694 } else {
2695 fp->enabled = true;
2696 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002697 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002698 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002699 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002700 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002701 }
2702
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002703 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002704}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002706#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2707 FIF_ALLMULTI | \
2708 FIF_FCSFAIL | \
2709 FIF_BCN_PRBRESP_PROMISC | \
2710 FIF_CONTROL | \
2711 FIF_OTHER_BSS)
2712
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2714 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002715 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002717 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002718 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002719 struct wl12xx_vif *wlvif;
Eliad Peller536129c82011-10-05 11:55:45 +02002720
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002721 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722
Arik Nemtsov7d057862010-10-16 19:25:35 +02002723 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2724 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002726 mutex_lock(&wl->mutex);
2727
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002728 *total &= WL1271_SUPPORTED_FILTERS;
2729 changed &= WL1271_SUPPORTED_FILTERS;
2730
2731 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002732 goto out;
2733
Ido Yariva6208652011-03-01 15:14:41 +02002734 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002735 if (ret < 0)
2736 goto out;
2737
Eliad Peller6e8cd332011-10-10 10:13:13 +02002738 wl12xx_for_each_wlvif(wl, wlvif) {
2739 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2740 if (*total & FIF_ALLMULTI)
2741 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2742 false,
2743 NULL, 0);
2744 else if (fp)
2745 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2746 fp->enabled,
2747 fp->mc_list,
2748 fp->mc_list_length);
2749 if (ret < 0)
2750 goto out_sleep;
2751 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002752 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002753
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002754 /*
2755 * the fw doesn't provide an api to configure the filters. instead,
2756 * the filters configuration is based on the active roles / ROC
2757 * state.
2758 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002759
2760out_sleep:
2761 wl1271_ps_elp_sleep(wl);
2762
2763out:
2764 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002765 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766}
2767
Eliad Peller170d0e62011-10-05 11:56:06 +02002768static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2769 u8 id, u8 key_type, u8 key_size,
2770 const u8 *key, u8 hlid, u32 tx_seq_32,
2771 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002772{
2773 struct wl1271_ap_key *ap_key;
2774 int i;
2775
2776 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2777
2778 if (key_size > MAX_KEY_SIZE)
2779 return -EINVAL;
2780
2781 /*
2782 * Find next free entry in ap_keys. Also check we are not replacing
2783 * an existing key.
2784 */
2785 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002786 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 break;
2788
Eliad Peller170d0e62011-10-05 11:56:06 +02002789 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002790 wl1271_warning("trying to record key replacement");
2791 return -EINVAL;
2792 }
2793 }
2794
2795 if (i == MAX_NUM_KEYS)
2796 return -EBUSY;
2797
2798 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2799 if (!ap_key)
2800 return -ENOMEM;
2801
2802 ap_key->id = id;
2803 ap_key->key_type = key_type;
2804 ap_key->key_size = key_size;
2805 memcpy(ap_key->key, key, key_size);
2806 ap_key->hlid = hlid;
2807 ap_key->tx_seq_32 = tx_seq_32;
2808 ap_key->tx_seq_16 = tx_seq_16;
2809
Eliad Peller170d0e62011-10-05 11:56:06 +02002810 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002811 return 0;
2812}
2813
Eliad Peller170d0e62011-10-05 11:56:06 +02002814static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002815{
2816 int i;
2817
2818 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002819 kfree(wlvif->ap.recorded_keys[i]);
2820 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 }
2822}
2823
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002824static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825{
2826 int i, ret = 0;
2827 struct wl1271_ap_key *key;
2828 bool wep_key_added = false;
2829
2830 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002831 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002832 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002833 break;
2834
Eliad Peller170d0e62011-10-05 11:56:06 +02002835 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002836 hlid = key->hlid;
2837 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002838 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002839
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002840 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002841 key->id, key->key_type,
2842 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002843 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002844 key->tx_seq_16);
2845 if (ret < 0)
2846 goto out;
2847
2848 if (key->key_type == KEY_WEP)
2849 wep_key_added = true;
2850 }
2851
2852 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002853 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002854 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002855 if (ret < 0)
2856 goto out;
2857 }
2858
2859out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002860 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 return ret;
2862}
2863
Eliad Peller536129c82011-10-05 11:55:45 +02002864static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2865 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002866 u8 key_size, const u8 *key, u32 tx_seq_32,
2867 u16 tx_seq_16, struct ieee80211_sta *sta)
2868{
2869 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002870 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002871
2872 if (is_ap) {
2873 struct wl1271_station *wl_sta;
2874 u8 hlid;
2875
2876 if (sta) {
2877 wl_sta = (struct wl1271_station *)sta->drv_priv;
2878 hlid = wl_sta->hlid;
2879 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002880 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002881 }
2882
Eliad Peller53d40d02011-10-10 10:13:02 +02002883 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002884 /*
2885 * We do not support removing keys after AP shutdown.
2886 * Pretend we do to make mac80211 happy.
2887 */
2888 if (action != KEY_ADD_OR_REPLACE)
2889 return 0;
2890
Eliad Peller170d0e62011-10-05 11:56:06 +02002891 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002892 key_type, key_size,
2893 key, hlid, tx_seq_32,
2894 tx_seq_16);
2895 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002896 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002897 id, key_type, key_size,
2898 key, hlid, tx_seq_32,
2899 tx_seq_16);
2900 }
2901
2902 if (ret < 0)
2903 return ret;
2904 } else {
2905 const u8 *addr;
2906 static const u8 bcast_addr[ETH_ALEN] = {
2907 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2908 };
2909
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002910 /*
2911 * A STA set to GEM cipher requires 2 tx spare blocks.
2912 * Return to default value when GEM cipher key is removed
2913 */
2914 if (key_type == KEY_GEM) {
2915 if (action == KEY_ADD_OR_REPLACE)
2916 wl->tx_spare_blocks = 2;
2917 else if (action == KEY_REMOVE)
2918 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2919 }
2920
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002921 addr = sta ? sta->addr : bcast_addr;
2922
2923 if (is_zero_ether_addr(addr)) {
2924 /* We dont support TX only encryption */
2925 return -EOPNOTSUPP;
2926 }
2927
2928 /* The wl1271 does not allow to remove unicast keys - they
2929 will be cleared automatically on next CMD_JOIN. Ignore the
2930 request silently, as we dont want the mac80211 to emit
2931 an error message. */
2932 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2933 return 0;
2934
Eliad Peller010d3d32011-08-14 13:17:31 +03002935 /* don't remove key if hlid was already deleted */
2936 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002937 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002938 return 0;
2939
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002940 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002941 id, key_type, key_size,
2942 key, addr, tx_seq_32,
2943 tx_seq_16);
2944 if (ret < 0)
2945 return ret;
2946
2947 /* the default WEP key needs to be configured at least once */
2948 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002949 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002950 wlvif->default_key,
2951 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002952 if (ret < 0)
2953 return ret;
2954 }
2955 }
2956
2957 return 0;
2958}
2959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2961 struct ieee80211_vif *vif,
2962 struct ieee80211_sta *sta,
2963 struct ieee80211_key_conf *key_conf)
2964{
2965 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002966 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002968 u32 tx_seq_32 = 0;
2969 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 u8 key_type;
2971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2973
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002974 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002976 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977 key_conf->keylen, key_conf->flags);
2978 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 mutex_lock(&wl->mutex);
2981
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002982 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2983 ret = -EAGAIN;
2984 goto out_unlock;
2985 }
2986
Ido Yariva6208652011-03-01 15:14:41 +02002987 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 if (ret < 0)
2989 goto out_unlock;
2990
Johannes Berg97359d12010-08-10 09:46:38 +02002991 switch (key_conf->cipher) {
2992 case WLAN_CIPHER_SUITE_WEP40:
2993 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994 key_type = KEY_WEP;
2995
2996 key_conf->hw_key_idx = key_conf->keyidx;
2997 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002998 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 key_type = KEY_TKIP;
3000
3001 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02003002 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3003 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003004 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003005 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006 key_type = KEY_AES;
3007
3008 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02003009 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3010 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003012 case WL1271_CIPHER_SUITE_GEM:
3013 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02003014 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3015 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003016 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003018 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019
3020 ret = -EOPNOTSUPP;
3021 goto out_sleep;
3022 }
3023
3024 switch (cmd) {
3025 case SET_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02003026 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003027 key_conf->keyidx, key_type,
3028 key_conf->keylen, key_conf->key,
3029 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 if (ret < 0) {
3031 wl1271_error("Could not add or replace key");
3032 goto out_sleep;
3033 }
3034 break;
3035
3036 case DISABLE_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02003037 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003038 key_conf->keyidx, key_type,
3039 key_conf->keylen, key_conf->key,
3040 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041 if (ret < 0) {
3042 wl1271_error("Could not remove key");
3043 goto out_sleep;
3044 }
3045 break;
3046
3047 default:
3048 wl1271_error("Unsupported key cmd 0x%x", cmd);
3049 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050 break;
3051 }
3052
3053out_sleep:
3054 wl1271_ps_elp_sleep(wl);
3055
3056out_unlock:
3057 mutex_unlock(&wl->mutex);
3058
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 return ret;
3060}
3061
3062static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003063 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003064 struct cfg80211_scan_request *req)
3065{
3066 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003067 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3068
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003069 int ret;
3070 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003071 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072
3073 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3074
3075 if (req->n_ssids) {
3076 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003077 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003078 }
3079
3080 mutex_lock(&wl->mutex);
3081
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003082 if (wl->state == WL1271_STATE_OFF) {
3083 /*
3084 * We cannot return -EBUSY here because cfg80211 will expect
3085 * a call to ieee80211_scan_completed if we do - in this case
3086 * there won't be any call.
3087 */
3088 ret = -EAGAIN;
3089 goto out;
3090 }
3091
Ido Yariva6208652011-03-01 15:14:41 +02003092 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003093 if (ret < 0)
3094 goto out;
3095
Eliad Peller251c1772011-08-14 13:17:17 +03003096 /* cancel ROC before scanning */
3097 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f62011-10-10 10:13:00 +02003098 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003099 /* don't allow scanning right now */
3100 ret = -EBUSY;
3101 goto out_sleep;
3102 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003103 wl12xx_croc(wl, wlvif->dev_role_id);
3104 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003105 }
3106
Eliad Peller784f6942011-10-05 11:55:39 +02003107 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003108out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003110out:
3111 mutex_unlock(&wl->mutex);
3112
3113 return ret;
3114}
3115
Eliad Peller73ecce32011-06-27 13:06:45 +03003116static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3117 struct ieee80211_vif *vif)
3118{
3119 struct wl1271 *wl = hw->priv;
3120 int ret;
3121
3122 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3123
3124 mutex_lock(&wl->mutex);
3125
3126 if (wl->state == WL1271_STATE_OFF)
3127 goto out;
3128
3129 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3130 goto out;
3131
3132 ret = wl1271_ps_elp_wakeup(wl);
3133 if (ret < 0)
3134 goto out;
3135
3136 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3137 ret = wl1271_scan_stop(wl);
3138 if (ret < 0)
3139 goto out_sleep;
3140 }
3141 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3142 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003143 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003144 wl->scan.req = NULL;
3145 ieee80211_scan_completed(wl->hw, true);
3146
3147out_sleep:
3148 wl1271_ps_elp_sleep(wl);
3149out:
3150 mutex_unlock(&wl->mutex);
3151
3152 cancel_delayed_work_sync(&wl->scan_complete_work);
3153}
3154
Luciano Coelho33c2c062011-05-10 14:46:02 +03003155static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3156 struct ieee80211_vif *vif,
3157 struct cfg80211_sched_scan_request *req,
3158 struct ieee80211_sched_scan_ies *ies)
3159{
3160 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003161 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003162 int ret;
3163
3164 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3165
3166 mutex_lock(&wl->mutex);
3167
3168 ret = wl1271_ps_elp_wakeup(wl);
3169 if (ret < 0)
3170 goto out;
3171
Eliad Peller536129c82011-10-05 11:55:45 +02003172 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003173 if (ret < 0)
3174 goto out_sleep;
3175
Eliad Peller536129c82011-10-05 11:55:45 +02003176 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003177 if (ret < 0)
3178 goto out_sleep;
3179
3180 wl->sched_scanning = true;
3181
3182out_sleep:
3183 wl1271_ps_elp_sleep(wl);
3184out:
3185 mutex_unlock(&wl->mutex);
3186 return ret;
3187}
3188
3189static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3190 struct ieee80211_vif *vif)
3191{
3192 struct wl1271 *wl = hw->priv;
3193 int ret;
3194
3195 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3196
3197 mutex_lock(&wl->mutex);
3198
3199 ret = wl1271_ps_elp_wakeup(wl);
3200 if (ret < 0)
3201 goto out;
3202
3203 wl1271_scan_sched_scan_stop(wl);
3204
3205 wl1271_ps_elp_sleep(wl);
3206out:
3207 mutex_unlock(&wl->mutex);
3208}
3209
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003210static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3211{
3212 struct wl1271 *wl = hw->priv;
3213 int ret = 0;
3214
3215 mutex_lock(&wl->mutex);
3216
3217 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3218 ret = -EAGAIN;
3219 goto out;
3220 }
3221
Ido Yariva6208652011-03-01 15:14:41 +02003222 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003223 if (ret < 0)
3224 goto out;
3225
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003226 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003227 if (ret < 0)
3228 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3229
3230 wl1271_ps_elp_sleep(wl);
3231
3232out:
3233 mutex_unlock(&wl->mutex);
3234
3235 return ret;
3236}
3237
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003238static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3239{
3240 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003241 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003242 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243
3244 mutex_lock(&wl->mutex);
3245
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003246 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3247 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003248 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003249 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003250
Ido Yariva6208652011-03-01 15:14:41 +02003251 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003252 if (ret < 0)
3253 goto out;
3254
Eliad Peller6e8cd332011-10-10 10:13:13 +02003255 wl12xx_for_each_wlvif(wl, wlvif) {
3256 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3257 if (ret < 0)
3258 wl1271_warning("set rts threshold failed: %d", ret);
3259 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003260 wl1271_ps_elp_sleep(wl);
3261
3262out:
3263 mutex_unlock(&wl->mutex);
3264
3265 return ret;
3266}
3267
Eliad Peller1fe9f162011-10-05 11:55:48 +02003268static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003269 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003270{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003271 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003272 u8 ssid_len;
3273 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3274 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003275
Eliad Peller889cb362011-05-01 09:56:45 +03003276 if (!ptr) {
3277 wl1271_error("No SSID in IEs!");
3278 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003279 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003280
Eliad Peller889cb362011-05-01 09:56:45 +03003281 ssid_len = ptr[1];
3282 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3283 wl1271_error("SSID is too long!");
3284 return -EINVAL;
3285 }
3286
Eliad Peller1fe9f162011-10-05 11:55:48 +02003287 wlvif->ssid_len = ssid_len;
3288 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003289 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003290}
3291
Eliad Pellerd48055d2011-09-15 12:07:04 +03003292static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3293{
3294 int len;
3295 const u8 *next, *end = skb->data + skb->len;
3296 u8 *ie = (u8 *)cfg80211_find_ie(eid, 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
Eliad Peller26b4bf22011-09-15 12:07:05 +03003306static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3307 unsigned int oui, u8 oui_type,
3308 int ieoffset)
3309{
3310 int len;
3311 const u8 *next, *end = skb->data + skb->len;
3312 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3313 skb->data + ieoffset,
3314 skb->len - ieoffset);
3315 if (!ie)
3316 return;
3317 len = ie[1] + 2;
3318 next = ie + len;
3319 memmove(ie, next, end - next);
3320 skb_trim(skb, skb->len - len);
3321}
3322
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003323static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003324 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003325 u8 *probe_rsp_data,
3326 size_t probe_rsp_len,
3327 u32 rates)
3328{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003329 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3330 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003331 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3332 int ssid_ie_offset, ie_offset, templ_len;
3333 const u8 *ptr;
3334
3335 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003336 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003337 return wl1271_cmd_template_set(wl,
3338 CMD_TEMPL_AP_PROBE_RESPONSE,
3339 probe_rsp_data,
3340 probe_rsp_len, 0,
3341 rates);
3342
3343 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3344 wl1271_error("probe_rsp template too big");
3345 return -EINVAL;
3346 }
3347
3348 /* start searching from IE offset */
3349 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3350
3351 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3352 probe_rsp_len - ie_offset);
3353 if (!ptr) {
3354 wl1271_error("No SSID in beacon!");
3355 return -EINVAL;
3356 }
3357
3358 ssid_ie_offset = ptr - probe_rsp_data;
3359 ptr += (ptr[1] + 2);
3360
3361 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3362
3363 /* insert SSID from bss_conf */
3364 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3365 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3366 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3367 bss_conf->ssid, bss_conf->ssid_len);
3368 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3369
3370 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3371 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3372 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3373
3374 return wl1271_cmd_template_set(wl,
3375 CMD_TEMPL_AP_PROBE_RESPONSE,
3376 probe_rsp_templ,
3377 templ_len, 0,
3378 rates);
3379}
3380
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003382 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003383 struct ieee80211_bss_conf *bss_conf,
3384 u32 changed)
3385{
Eliad Peller0603d892011-10-05 11:55:51 +02003386 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003387 int ret = 0;
3388
3389 if (changed & BSS_CHANGED_ERP_SLOT) {
3390 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003391 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 else
Eliad Peller0603d892011-10-05 11:55:51 +02003393 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 if (ret < 0) {
3395 wl1271_warning("Set slot time failed %d", ret);
3396 goto out;
3397 }
3398 }
3399
3400 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3401 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003402 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003403 else
Eliad Peller0603d892011-10-05 11:55:51 +02003404 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 }
3406
3407 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3408 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003409 ret = wl1271_acx_cts_protect(wl, wlvif,
3410 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 else
Eliad Peller0603d892011-10-05 11:55:51 +02003412 ret = wl1271_acx_cts_protect(wl, wlvif,
3413 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if (ret < 0) {
3415 wl1271_warning("Set ctsprotect failed %d", ret);
3416 goto out;
3417 }
3418 }
3419
3420out:
3421 return ret;
3422}
3423
3424static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3425 struct ieee80211_vif *vif,
3426 struct ieee80211_bss_conf *bss_conf,
3427 u32 changed)
3428{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003429 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003430 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003431 int ret = 0;
3432
3433 if ((changed & BSS_CHANGED_BEACON_INT)) {
3434 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3435 bss_conf->beacon_int);
3436
Eliad Peller6a899792011-10-05 11:55:58 +02003437 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 }
3439
3440 if ((changed & BSS_CHANGED_BEACON)) {
3441 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003442 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003443 int ieoffset = offsetof(struct ieee80211_mgmt,
3444 u.beacon.variable);
3445 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3446 u16 tmpl_id;
3447
3448 if (!beacon)
3449 goto out;
3450
3451 wl1271_debug(DEBUG_MASTER, "beacon updated");
3452
Eliad Peller1fe9f162011-10-05 11:55:48 +02003453 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454 if (ret < 0) {
3455 dev_kfree_skb(beacon);
3456 goto out;
3457 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003458 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003459 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3460 CMD_TEMPL_BEACON;
3461 ret = wl1271_cmd_template_set(wl, tmpl_id,
3462 beacon->data,
3463 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003464 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003465 if (ret < 0) {
3466 dev_kfree_skb(beacon);
3467 goto out;
3468 }
3469
Eliad Pellerd48055d2011-09-15 12:07:04 +03003470 /* remove TIM ie from probe response */
3471 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3472
Eliad Peller26b4bf22011-09-15 12:07:05 +03003473 /*
3474 * remove p2p ie from probe response.
3475 * the fw reponds to probe requests that don't include
3476 * the p2p ie. probe requests with p2p ie will be passed,
3477 * and will be responded by the supplicant (the spec
3478 * forbids including the p2p ie when responding to probe
3479 * requests that didn't include it).
3480 */
3481 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3482 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3483
Arik Nemtsove78a2872010-10-16 19:07:21 +02003484 hdr = (struct ieee80211_hdr *) beacon->data;
3485 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3486 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003487 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003488 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003489 beacon->data,
3490 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003491 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003492 else
3493 ret = wl1271_cmd_template_set(wl,
3494 CMD_TEMPL_PROBE_RESPONSE,
3495 beacon->data,
3496 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003497 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 dev_kfree_skb(beacon);
3499 if (ret < 0)
3500 goto out;
3501 }
3502
3503out:
3504 return ret;
3505}
3506
3507/* AP mode changes */
3508static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003509 struct ieee80211_vif *vif,
3510 struct ieee80211_bss_conf *bss_conf,
3511 u32 changed)
3512{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003513 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003514 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003515
Arik Nemtsove78a2872010-10-16 19:07:21 +02003516 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3517 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003518
Eliad Peller87fbcb02011-10-05 11:55:41 +02003519 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003520 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003521 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003522 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003523
Eliad Peller87fbcb02011-10-05 11:55:41 +02003524 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003525 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003526 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003527 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003528 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003529
Eliad Peller784f6942011-10-05 11:55:39 +02003530 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003531 if (ret < 0)
3532 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003533 }
3534
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3536 if (ret < 0)
3537 goto out;
3538
3539 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3540 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003541 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003542 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 if (ret < 0)
3544 goto out;
3545
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003546 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003547 if (ret < 0)
3548 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003549
Eliad Peller53d40d02011-10-10 10:13:02 +02003550 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003551 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003552 }
3553 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003554 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003555 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003556 if (ret < 0)
3557 goto out;
3558
Eliad Peller53d40d02011-10-10 10:13:02 +02003559 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003560 wl1271_debug(DEBUG_AP, "stopped AP");
3561 }
3562 }
3563 }
3564
Eliad Peller0603d892011-10-05 11:55:51 +02003565 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003566 if (ret < 0)
3567 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003568
3569 /* Handle HT information change */
3570 if ((changed & BSS_CHANGED_HT) &&
3571 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003572 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003573 bss_conf->ht_operation_mode);
3574 if (ret < 0) {
3575 wl1271_warning("Set ht information failed %d", ret);
3576 goto out;
3577 }
3578 }
3579
Arik Nemtsove78a2872010-10-16 19:07:21 +02003580out:
3581 return;
3582}
3583
3584/* STA/IBSS mode changes */
3585static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3586 struct ieee80211_vif *vif,
3587 struct ieee80211_bss_conf *bss_conf,
3588 u32 changed)
3589{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003590 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003591 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003592 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003593 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003594 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003595 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003596 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003597 bool sta_exists = false;
3598 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003599
3600 if (is_ibss) {
3601 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3602 changed);
3603 if (ret < 0)
3604 goto out;
3605 }
3606
Eliad Peller227e81e2011-08-14 13:17:26 +03003607 if (changed & BSS_CHANGED_IBSS) {
3608 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003609 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003610 ibss_joined = true;
3611 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003612 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3613 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003614 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003615 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003616 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003617 }
3618 }
3619 }
3620
3621 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003622 do_join = true;
3623
3624 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003625 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003626 do_join = true;
3627
Eliad Peller227e81e2011-08-14 13:17:26 +03003628 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003629 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3630 bss_conf->enable_beacon ? "enabled" : "disabled");
3631
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003632 do_join = true;
3633 }
3634
Arik Nemtsove78a2872010-10-16 19:07:21 +02003635 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003636 bool enable = false;
3637 if (bss_conf->cqm_rssi_thold)
3638 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003639 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003640 bss_conf->cqm_rssi_thold,
3641 bss_conf->cqm_rssi_hyst);
3642 if (ret < 0)
3643 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003644 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003645 }
3646
Eliad Pellercdf09492011-10-05 11:55:44 +02003647 if (changed & BSS_CHANGED_BSSID)
3648 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003649 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003650 if (ret < 0)
3651 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003652
Eliad Peller784f6942011-10-05 11:55:39 +02003653 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003654 if (ret < 0)
3655 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003656
Eliad Pellerfa287b82010-12-26 09:27:50 +01003657 /* Need to update the BSSID (for filtering etc) */
3658 do_join = true;
3659 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003660
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003661 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3662 rcu_read_lock();
3663 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3664 if (!sta)
3665 goto sta_not_found;
3666
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003667 /* save the supp_rates of the ap */
3668 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3669 if (sta->ht_cap.ht_supported)
3670 sta_rate_set |=
3671 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003672 sta_ht_cap = sta->ht_cap;
3673 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003674
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003675sta_not_found:
3676 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003677 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003678
Arik Nemtsove78a2872010-10-16 19:07:21 +02003679 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003680 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003681 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003682 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003683 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003684 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003685
Eliad Peller74ec8392011-10-05 11:56:02 +02003686 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003687
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003688 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003689 * use basic rates from AP, and determine lowest rate
3690 * to use with control frames.
3691 */
3692 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003693 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003694 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003695 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003696 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003697 wl1271_tx_min_rate_get(wl,
3698 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003700 wlvif->rate_set =
3701 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003702 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003703 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003704 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003705 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003706 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003707
3708 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003709 * with wl1271, we don't need to update the
3710 * beacon_int and dtim_period, because the firmware
3711 * updates it by itself when the first beacon is
3712 * received after a join.
3713 */
Eliad Peller6840e372011-10-05 11:55:50 +02003714 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003716 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003717
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003718 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003719 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003720 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003721 dev_kfree_skb(wlvif->probereq);
3722 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003723 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003724 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003725 ieoffset = offsetof(struct ieee80211_mgmt,
3726 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003727 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003728
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003729 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003730 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003731 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003732 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003733 } else {
3734 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003735 bool was_assoc =
Eliad Pellerba8447f62011-10-10 10:13:00 +02003736 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3737 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003738 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003739 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3740 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003741 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003742
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003743 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003744 dev_kfree_skb(wlvif->probereq);
3745 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003746
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003747 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003748 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003749
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003750 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003751 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003752 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003753 wl1271_tx_min_rate_get(wl,
3754 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003755 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003756 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003757 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003758
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003759 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003760 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003761
3762 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003763 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003764 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003765 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003766
3767 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003768 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003769 u32 conf_flags = wl->hw->conf.flags;
3770 /*
3771 * we might have to disable roc, if there was
3772 * no IF_OPER_UP notification.
3773 */
3774 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003775 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003776 if (ret < 0)
3777 goto out;
3778 }
3779 /*
3780 * (we also need to disable roc in case of
3781 * roaming on the same channel. until we will
3782 * have a better flow...)
3783 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003784 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3785 ret = wl12xx_croc(wl,
3786 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003787 if (ret < 0)
3788 goto out;
3789 }
3790
Eliad Peller0603d892011-10-05 11:55:51 +02003791 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003792 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003793 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003794 wl12xx_roc(wl, wlvif,
3795 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003796 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003797 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003798 }
3799 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003800
Eliad Pellerd192d262011-05-24 14:33:08 +03003801 if (changed & BSS_CHANGED_IBSS) {
3802 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3803 bss_conf->ibss_joined);
3804
3805 if (bss_conf->ibss_joined) {
3806 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003807 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003808 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003809 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003810 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003811 wl1271_tx_min_rate_get(wl,
3812 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003813
Shahar Levi06b660e2011-09-05 13:54:36 +03003814 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003815 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3816 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003817 if (ret < 0)
3818 goto out;
3819 }
3820 }
3821
Eliad Peller0603d892011-10-05 11:55:51 +02003822 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003823 if (ret < 0)
3824 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003825
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003826 if (changed & BSS_CHANGED_ARP_FILTER) {
3827 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003828 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003829
Eliad Pellerc5312772010-12-09 11:31:27 +02003830 if (bss_conf->arp_addr_cnt == 1 &&
3831 bss_conf->arp_filter_enabled) {
3832 /*
3833 * The template should have been configured only upon
3834 * association. however, it seems that the correct ip
3835 * isn't being set (when sending), so we have to
3836 * reconfigure the template upon every ip change.
3837 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003838 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003839 if (ret < 0) {
3840 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003841 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003842 }
3843
Eliad Peller0603d892011-10-05 11:55:51 +02003844 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003845 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003846 addr);
3847 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003848 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003849
3850 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003851 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003852 }
3853
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003854 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003855 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003856 if (ret < 0) {
3857 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003858 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003859 }
Eliad Peller251c1772011-08-14 13:17:17 +03003860
3861 /* ROC until connected (after EAPOL exchange) */
3862 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003863 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003864 if (ret < 0)
3865 goto out;
3866
Eliad Pellerba8447f62011-10-10 10:13:00 +02003867 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003868 ieee80211_get_operstate(vif));
3869 }
3870 /*
3871 * stop device role if started (we might already be in
3872 * STA role). TODO: make it better.
3873 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003874 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3875 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003876 if (ret < 0)
3877 goto out;
3878
Eliad Peller7edebf52011-10-05 11:55:52 +02003879 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003880 if (ret < 0)
3881 goto out;
3882 }
Eliad Peller05dba352011-08-23 16:37:01 +03003883
3884 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003885 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3886 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003887 enum wl1271_cmd_ps_mode mode;
3888
3889 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003890 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003891 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003892 true);
3893 if (ret < 0)
3894 goto out;
3895 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003896 }
3897
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003898 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003899 if (sta_exists) {
3900 if ((changed & BSS_CHANGED_HT) &&
3901 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003902 ret = wl1271_acx_set_ht_capabilities(wl,
3903 &sta_ht_cap,
3904 true,
Eliad Peller154da672011-10-05 11:55:53 +02003905 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003906 if (ret < 0) {
3907 wl1271_warning("Set ht cap true failed %d",
3908 ret);
3909 goto out;
3910 }
3911 }
3912 /* handle new association without HT and disassociation */
3913 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003914 ret = wl1271_acx_set_ht_capabilities(wl,
3915 &sta_ht_cap,
3916 false,
Eliad Peller154da672011-10-05 11:55:53 +02003917 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003918 if (ret < 0) {
3919 wl1271_warning("Set ht cap false failed %d",
3920 ret);
3921 goto out;
3922 }
3923 }
3924 }
3925
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003926 /* Handle HT information change. Done after join. */
3927 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003928 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003929 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003930 bss_conf->ht_operation_mode);
3931 if (ret < 0) {
3932 wl1271_warning("Set ht information failed %d", ret);
3933 goto out;
3934 }
3935 }
3936
Arik Nemtsove78a2872010-10-16 19:07:21 +02003937out:
3938 return;
3939}
3940
3941static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3942 struct ieee80211_vif *vif,
3943 struct ieee80211_bss_conf *bss_conf,
3944 u32 changed)
3945{
3946 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003947 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3948 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003949 int ret;
3950
3951 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3952 (int)changed);
3953
3954 mutex_lock(&wl->mutex);
3955
3956 if (unlikely(wl->state == WL1271_STATE_OFF))
3957 goto out;
3958
Eliad Peller10c8cd02011-10-10 10:13:06 +02003959 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3960 goto out;
3961
Ido Yariva6208652011-03-01 15:14:41 +02003962 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003963 if (ret < 0)
3964 goto out;
3965
3966 if (is_ap)
3967 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3968 else
3969 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971 wl1271_ps_elp_sleep(wl);
3972
3973out:
3974 mutex_unlock(&wl->mutex);
3975}
3976
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003977static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3978 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003979 const struct ieee80211_tx_queue_params *params)
3980{
3981 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003982 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003983 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003984 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003985
3986 mutex_lock(&wl->mutex);
3987
3988 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3989
Kalle Valo4695dc92010-03-18 12:26:38 +02003990 if (params->uapsd)
3991 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3992 else
3993 ps_scheme = CONF_PS_SCHEME_LEGACY;
3994
Arik Nemtsov488fc542010-10-16 20:33:45 +02003995 if (wl->state == WL1271_STATE_OFF) {
3996 /*
3997 * If the state is off, the parameters will be recorded and
3998 * configured on init. This happens in AP-mode.
3999 */
4000 struct conf_tx_ac_category *conf_ac =
4001 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
4002 struct conf_tx_tid *conf_tid =
4003 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
4004
4005 conf_ac->ac = wl1271_tx_get_queue(queue);
4006 conf_ac->cw_min = (u8)params->cw_min;
4007 conf_ac->cw_max = params->cw_max;
4008 conf_ac->aifsn = params->aifs;
4009 conf_ac->tx_op_limit = params->txop << 5;
4010
4011 conf_tid->queue_id = wl1271_tx_get_queue(queue);
4012 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
4013 conf_tid->tsid = wl1271_tx_get_queue(queue);
4014 conf_tid->ps_scheme = ps_scheme;
4015 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4016 conf_tid->apsd_conf[0] = 0;
4017 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004018 goto out;
4019 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004020
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004021 ret = wl1271_ps_elp_wakeup(wl);
4022 if (ret < 0)
4023 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004024
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004025 /*
4026 * the txop is confed in units of 32us by the mac80211,
4027 * we need us
4028 */
Eliad Peller0603d892011-10-05 11:55:51 +02004029 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004030 params->cw_min, params->cw_max,
4031 params->aifs, params->txop << 5);
4032 if (ret < 0)
4033 goto out_sleep;
4034
Eliad Peller0603d892011-10-05 11:55:51 +02004035 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004036 CONF_CHANNEL_TYPE_EDCF,
4037 wl1271_tx_get_queue(queue),
4038 ps_scheme, CONF_ACK_POLICY_LEGACY,
4039 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004040
4041out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004042 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004043
4044out:
4045 mutex_unlock(&wl->mutex);
4046
4047 return ret;
4048}
4049
Eliad Peller37a41b42011-09-21 14:06:11 +03004050static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4051 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004052{
4053
4054 struct wl1271 *wl = hw->priv;
4055 u64 mactime = ULLONG_MAX;
4056 int ret;
4057
4058 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4059
4060 mutex_lock(&wl->mutex);
4061
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004062 if (unlikely(wl->state == WL1271_STATE_OFF))
4063 goto out;
4064
Ido Yariva6208652011-03-01 15:14:41 +02004065 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004066 if (ret < 0)
4067 goto out;
4068
4069 ret = wl1271_acx_tsf_info(wl, &mactime);
4070 if (ret < 0)
4071 goto out_sleep;
4072
4073out_sleep:
4074 wl1271_ps_elp_sleep(wl);
4075
4076out:
4077 mutex_unlock(&wl->mutex);
4078 return mactime;
4079}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004080
John W. Linvilleece550d2010-07-28 16:41:06 -04004081static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4082 struct survey_info *survey)
4083{
4084 struct wl1271 *wl = hw->priv;
4085 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004086
John W. Linvilleece550d2010-07-28 16:41:06 -04004087 if (idx != 0)
4088 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004089
John W. Linvilleece550d2010-07-28 16:41:06 -04004090 survey->channel = conf->channel;
4091 survey->filled = SURVEY_INFO_NOISE_DBM;
4092 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004093
John W. Linvilleece550d2010-07-28 16:41:06 -04004094 return 0;
4095}
4096
Arik Nemtsov409622e2011-02-23 00:22:29 +02004097static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004098 struct wl12xx_vif *wlvif,
4099 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004100{
4101 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004102 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004103
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004104
4105 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106 wl1271_warning("could not allocate HLID - too much stations");
4107 return -EBUSY;
4108 }
4109
4110 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004111 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4112 if (ret < 0) {
4113 wl1271_warning("could not allocate HLID - too many links");
4114 return -EBUSY;
4115 }
4116
4117 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004118 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004119 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120 return 0;
4121}
4122
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004123void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004124{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004126 return;
4127
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004128 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004129 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004130 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004131 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004132 __clear_bit(hlid, &wl->ap_ps_map);
4133 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004134 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004135 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004136}
4137
4138static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4139 struct ieee80211_vif *vif,
4140 struct ieee80211_sta *sta)
4141{
4142 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004143 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004144 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004145 int ret = 0;
4146 u8 hlid;
4147
4148 mutex_lock(&wl->mutex);
4149
4150 if (unlikely(wl->state == WL1271_STATE_OFF))
4151 goto out;
4152
Eliad Peller536129c82011-10-05 11:55:45 +02004153 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004154 goto out;
4155
4156 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4157
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004158 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004159 if (ret < 0)
4160 goto out;
4161
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004162 wl_sta = (struct wl1271_station *)sta->drv_priv;
4163 hlid = wl_sta->hlid;
4164
Ido Yariva6208652011-03-01 15:14:41 +02004165 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004166 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004167 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004168
Eliad Peller1b92f152011-10-10 10:13:09 +02004169 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004170 if (ret < 0)
4171 goto out_sleep;
4172
Eliad Pellerb67476e2011-08-14 13:17:23 +03004173 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4174 if (ret < 0)
4175 goto out_sleep;
4176
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004177 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4178 if (ret < 0)
4179 goto out_sleep;
4180
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004181out_sleep:
4182 wl1271_ps_elp_sleep(wl);
4183
Arik Nemtsov409622e2011-02-23 00:22:29 +02004184out_free_sta:
4185 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004186 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004187
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004188out:
4189 mutex_unlock(&wl->mutex);
4190 return ret;
4191}
4192
4193static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4194 struct ieee80211_vif *vif,
4195 struct ieee80211_sta *sta)
4196{
4197 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004198 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004199 struct wl1271_station *wl_sta;
4200 int ret = 0, id;
4201
4202 mutex_lock(&wl->mutex);
4203
4204 if (unlikely(wl->state == WL1271_STATE_OFF))
4205 goto out;
4206
Eliad Peller536129c82011-10-05 11:55:45 +02004207 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004208 goto out;
4209
4210 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4211
4212 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004213 id = wl_sta->hlid;
4214 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004215 goto out;
4216
Ido Yariva6208652011-03-01 15:14:41 +02004217 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004218 if (ret < 0)
4219 goto out;
4220
Eliad Pellerc690ec82011-08-14 13:17:07 +03004221 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004222 if (ret < 0)
4223 goto out_sleep;
4224
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004225 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004226
4227out_sleep:
4228 wl1271_ps_elp_sleep(wl);
4229
4230out:
4231 mutex_unlock(&wl->mutex);
4232 return ret;
4233}
4234
Luciano Coelho4623ec72011-03-21 19:26:41 +02004235static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4236 struct ieee80211_vif *vif,
4237 enum ieee80211_ampdu_mlme_action action,
4238 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4239 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004240{
4241 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004242 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004243 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004244 u8 hlid, *ba_bitmap;
4245
4246 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4247 tid);
4248
4249 /* sanity check - the fields in FW are only 8bits wide */
4250 if (WARN_ON(tid > 0xFF))
4251 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004252
4253 mutex_lock(&wl->mutex);
4254
4255 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4256 ret = -EAGAIN;
4257 goto out;
4258 }
4259
Eliad Peller536129c82011-10-05 11:55:45 +02004260 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004261 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004262 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004263 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004264 struct wl1271_station *wl_sta;
4265
4266 wl_sta = (struct wl1271_station *)sta->drv_priv;
4267 hlid = wl_sta->hlid;
4268 ba_bitmap = &wl->links[hlid].ba_bitmap;
4269 } else {
4270 ret = -EINVAL;
4271 goto out;
4272 }
4273
Ido Yariva6208652011-03-01 15:14:41 +02004274 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004275 if (ret < 0)
4276 goto out;
4277
Shahar Levi70559a02011-05-22 16:10:22 +03004278 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4279 tid, action);
4280
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004281 switch (action) {
4282 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004283 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004284 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004285 break;
4286 }
4287
4288 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4289 ret = -EBUSY;
4290 wl1271_error("exceeded max RX BA sessions");
4291 break;
4292 }
4293
4294 if (*ba_bitmap & BIT(tid)) {
4295 ret = -EINVAL;
4296 wl1271_error("cannot enable RX BA session on active "
4297 "tid: %d", tid);
4298 break;
4299 }
4300
4301 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4302 hlid);
4303 if (!ret) {
4304 *ba_bitmap |= BIT(tid);
4305 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004306 }
4307 break;
4308
4309 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004310 if (!(*ba_bitmap & BIT(tid))) {
4311 ret = -EINVAL;
4312 wl1271_error("no active RX BA session on tid: %d",
4313 tid);
4314 break;
4315 }
4316
4317 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4318 hlid);
4319 if (!ret) {
4320 *ba_bitmap &= ~BIT(tid);
4321 wl->ba_rx_session_count--;
4322 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004323 break;
4324
4325 /*
4326 * The BA initiator session management in FW independently.
4327 * Falling break here on purpose for all TX APDU commands.
4328 */
4329 case IEEE80211_AMPDU_TX_START:
4330 case IEEE80211_AMPDU_TX_STOP:
4331 case IEEE80211_AMPDU_TX_OPERATIONAL:
4332 ret = -EINVAL;
4333 break;
4334
4335 default:
4336 wl1271_error("Incorrect ampdu action id=%x\n", action);
4337 ret = -EINVAL;
4338 }
4339
4340 wl1271_ps_elp_sleep(wl);
4341
4342out:
4343 mutex_unlock(&wl->mutex);
4344
4345 return ret;
4346}
4347
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004348static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4349 struct ieee80211_vif *vif,
4350 const struct cfg80211_bitrate_mask *mask)
4351{
Eliad Peller83587502011-10-10 10:12:53 +02004352 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004353 struct wl1271 *wl = hw->priv;
4354 int i;
4355
4356 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4357 mask->control[NL80211_BAND_2GHZ].legacy,
4358 mask->control[NL80211_BAND_5GHZ].legacy);
4359
4360 mutex_lock(&wl->mutex);
4361
4362 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004363 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004364 wl1271_tx_enabled_rates_get(wl,
4365 mask->control[i].legacy,
4366 i);
4367 mutex_unlock(&wl->mutex);
4368
4369 return 0;
4370}
4371
Shahar Levi6d158ff2011-09-08 13:01:33 +03004372static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4373 struct ieee80211_channel_switch *ch_switch)
4374{
4375 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004376 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004377 int ret;
4378
4379 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4380
4381 mutex_lock(&wl->mutex);
4382
4383 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004384 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4385 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4386 ieee80211_chswitch_done(vif, false);
4387 }
4388 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389 }
4390
4391 ret = wl1271_ps_elp_wakeup(wl);
4392 if (ret < 0)
4393 goto out;
4394
Eliad Peller52630c52011-10-10 10:13:08 +02004395 /* TODO: change mac80211 to pass vif as param */
4396 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4397 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004398
Eliad Peller52630c52011-10-10 10:13:08 +02004399 if (!ret)
4400 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4401 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004402
4403 wl1271_ps_elp_sleep(wl);
4404
4405out:
4406 mutex_unlock(&wl->mutex);
4407}
4408
Arik Nemtsov33437892011-04-26 23:35:39 +03004409static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4410{
4411 struct wl1271 *wl = hw->priv;
4412 bool ret = false;
4413
4414 mutex_lock(&wl->mutex);
4415
4416 if (unlikely(wl->state == WL1271_STATE_OFF))
4417 goto out;
4418
4419 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004420 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004421out:
4422 mutex_unlock(&wl->mutex);
4423
4424 return ret;
4425}
4426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427/* can't be const, mac80211 writes to this */
4428static struct ieee80211_rate wl1271_rates[] = {
4429 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4436 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004437 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4438 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004439 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4440 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4444 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004448 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4449 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004451 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4452 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004454 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4455 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004457 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4458 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004459 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004460 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4461 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004462 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004463 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4464 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004466 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4467 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004468};
4469
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004470/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004472 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004473 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004474 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4475 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4476 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004477 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004478 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4479 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4480 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004481 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004482 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4483 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4484 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004485 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004486};
4487
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004488/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004489static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004490 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004491 7, /* CONF_HW_RXTX_RATE_MCS7 */
4492 6, /* CONF_HW_RXTX_RATE_MCS6 */
4493 5, /* CONF_HW_RXTX_RATE_MCS5 */
4494 4, /* CONF_HW_RXTX_RATE_MCS4 */
4495 3, /* CONF_HW_RXTX_RATE_MCS3 */
4496 2, /* CONF_HW_RXTX_RATE_MCS2 */
4497 1, /* CONF_HW_RXTX_RATE_MCS1 */
4498 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004499
4500 11, /* CONF_HW_RXTX_RATE_54 */
4501 10, /* CONF_HW_RXTX_RATE_48 */
4502 9, /* CONF_HW_RXTX_RATE_36 */
4503 8, /* CONF_HW_RXTX_RATE_24 */
4504
4505 /* TI-specific rate */
4506 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4507
4508 7, /* CONF_HW_RXTX_RATE_18 */
4509 6, /* CONF_HW_RXTX_RATE_12 */
4510 3, /* CONF_HW_RXTX_RATE_11 */
4511 5, /* CONF_HW_RXTX_RATE_9 */
4512 4, /* CONF_HW_RXTX_RATE_6 */
4513 2, /* CONF_HW_RXTX_RATE_5_5 */
4514 1, /* CONF_HW_RXTX_RATE_2 */
4515 0 /* CONF_HW_RXTX_RATE_1 */
4516};
4517
Shahar Levie8b03a22010-10-13 16:09:39 +02004518/* 11n STA capabilities */
4519#define HW_RX_HIGHEST_RATE 72
4520
Shahar Levi00d20102010-11-08 11:20:10 +00004521#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004522 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4523 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004524 .ht_supported = true, \
4525 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4526 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4527 .mcs = { \
4528 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4529 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4530 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4531 }, \
4532}
4533
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004534/* can't be const, mac80211 writes to this */
4535static struct ieee80211_supported_band wl1271_band_2ghz = {
4536 .channels = wl1271_channels,
4537 .n_channels = ARRAY_SIZE(wl1271_channels),
4538 .bitrates = wl1271_rates,
4539 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004540 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004541};
4542
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004543/* 5 GHz data rates for WL1273 */
4544static struct ieee80211_rate wl1271_rates_5ghz[] = {
4545 { .bitrate = 60,
4546 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4547 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4548 { .bitrate = 90,
4549 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4550 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4551 { .bitrate = 120,
4552 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4553 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4554 { .bitrate = 180,
4555 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4556 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4557 { .bitrate = 240,
4558 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4559 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4560 { .bitrate = 360,
4561 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4562 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4563 { .bitrate = 480,
4564 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4565 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4566 { .bitrate = 540,
4567 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4568 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4569};
4570
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004571/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004572static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004573 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4574 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4575 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4576 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4577 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4578 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4579 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4580 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4581 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4582 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4583 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4584 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4585 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4586 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4587 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4588 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4589 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4590 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4591 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4592 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4593 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4594 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4595 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4596 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4597 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4598 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4599 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4600 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4601 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4602 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4603 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4604 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4605 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4606 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004607};
4608
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004609/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004610static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004611 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004612 7, /* CONF_HW_RXTX_RATE_MCS7 */
4613 6, /* CONF_HW_RXTX_RATE_MCS6 */
4614 5, /* CONF_HW_RXTX_RATE_MCS5 */
4615 4, /* CONF_HW_RXTX_RATE_MCS4 */
4616 3, /* CONF_HW_RXTX_RATE_MCS3 */
4617 2, /* CONF_HW_RXTX_RATE_MCS2 */
4618 1, /* CONF_HW_RXTX_RATE_MCS1 */
4619 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004620
4621 7, /* CONF_HW_RXTX_RATE_54 */
4622 6, /* CONF_HW_RXTX_RATE_48 */
4623 5, /* CONF_HW_RXTX_RATE_36 */
4624 4, /* CONF_HW_RXTX_RATE_24 */
4625
4626 /* TI-specific rate */
4627 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4628
4629 3, /* CONF_HW_RXTX_RATE_18 */
4630 2, /* CONF_HW_RXTX_RATE_12 */
4631 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4632 1, /* CONF_HW_RXTX_RATE_9 */
4633 0, /* CONF_HW_RXTX_RATE_6 */
4634 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4635 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4636 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4637};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004638
4639static struct ieee80211_supported_band wl1271_band_5ghz = {
4640 .channels = wl1271_channels_5ghz,
4641 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4642 .bitrates = wl1271_rates_5ghz,
4643 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004644 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004645};
4646
Tobias Klausera0ea9492010-05-20 10:38:11 +02004647static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004648 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4649 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4650};
4651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652static const struct ieee80211_ops wl1271_ops = {
4653 .start = wl1271_op_start,
4654 .stop = wl1271_op_stop,
4655 .add_interface = wl1271_op_add_interface,
4656 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004657#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004658 .suspend = wl1271_op_suspend,
4659 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004660#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004661 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004662 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004663 .configure_filter = wl1271_op_configure_filter,
4664 .tx = wl1271_op_tx,
4665 .set_key = wl1271_op_set_key,
4666 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004667 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004668 .sched_scan_start = wl1271_op_sched_scan_start,
4669 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004670 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004671 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004672 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004673 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004674 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004675 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004676 .sta_add = wl1271_op_sta_add,
4677 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004678 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004679 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004680 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004681 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004682 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004683};
4684
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004685
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004686u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004687{
4688 u8 idx;
4689
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004690 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004691
4692 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4693 wl1271_error("Illegal RX rate from HW: %d", rate);
4694 return 0;
4695 }
4696
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004697 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004698 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4699 wl1271_error("Unsupported RX rate from HW: %d", rate);
4700 return 0;
4701 }
4702
4703 return idx;
4704}
4705
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004706static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4707 struct device_attribute *attr,
4708 char *buf)
4709{
4710 struct wl1271 *wl = dev_get_drvdata(dev);
4711 ssize_t len;
4712
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004713 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004714
4715 mutex_lock(&wl->mutex);
4716 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4717 wl->sg_enabled);
4718 mutex_unlock(&wl->mutex);
4719
4720 return len;
4721
4722}
4723
4724static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4725 struct device_attribute *attr,
4726 const char *buf, size_t count)
4727{
4728 struct wl1271 *wl = dev_get_drvdata(dev);
4729 unsigned long res;
4730 int ret;
4731
Luciano Coelho6277ed62011-04-01 17:49:54 +03004732 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004733 if (ret < 0) {
4734 wl1271_warning("incorrect value written to bt_coex_mode");
4735 return count;
4736 }
4737
4738 mutex_lock(&wl->mutex);
4739
4740 res = !!res;
4741
4742 if (res == wl->sg_enabled)
4743 goto out;
4744
4745 wl->sg_enabled = res;
4746
4747 if (wl->state == WL1271_STATE_OFF)
4748 goto out;
4749
Ido Yariva6208652011-03-01 15:14:41 +02004750 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004751 if (ret < 0)
4752 goto out;
4753
4754 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4755 wl1271_ps_elp_sleep(wl);
4756
4757 out:
4758 mutex_unlock(&wl->mutex);
4759 return count;
4760}
4761
4762static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4763 wl1271_sysfs_show_bt_coex_state,
4764 wl1271_sysfs_store_bt_coex_state);
4765
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004766static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4767 struct device_attribute *attr,
4768 char *buf)
4769{
4770 struct wl1271 *wl = dev_get_drvdata(dev);
4771 ssize_t len;
4772
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004773 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004774
4775 mutex_lock(&wl->mutex);
4776 if (wl->hw_pg_ver >= 0)
4777 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4778 else
4779 len = snprintf(buf, len, "n/a\n");
4780 mutex_unlock(&wl->mutex);
4781
4782 return len;
4783}
4784
Gery Kahn6f07b722011-07-18 14:21:49 +03004785static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004786 wl1271_sysfs_show_hw_pg_ver, NULL);
4787
Ido Yariv95dac04f2011-06-06 14:57:06 +03004788static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4789 struct bin_attribute *bin_attr,
4790 char *buffer, loff_t pos, size_t count)
4791{
4792 struct device *dev = container_of(kobj, struct device, kobj);
4793 struct wl1271 *wl = dev_get_drvdata(dev);
4794 ssize_t len;
4795 int ret;
4796
4797 ret = mutex_lock_interruptible(&wl->mutex);
4798 if (ret < 0)
4799 return -ERESTARTSYS;
4800
4801 /* Let only one thread read the log at a time, blocking others */
4802 while (wl->fwlog_size == 0) {
4803 DEFINE_WAIT(wait);
4804
4805 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4806 &wait,
4807 TASK_INTERRUPTIBLE);
4808
4809 if (wl->fwlog_size != 0) {
4810 finish_wait(&wl->fwlog_waitq, &wait);
4811 break;
4812 }
4813
4814 mutex_unlock(&wl->mutex);
4815
4816 schedule();
4817 finish_wait(&wl->fwlog_waitq, &wait);
4818
4819 if (signal_pending(current))
4820 return -ERESTARTSYS;
4821
4822 ret = mutex_lock_interruptible(&wl->mutex);
4823 if (ret < 0)
4824 return -ERESTARTSYS;
4825 }
4826
4827 /* Check if the fwlog is still valid */
4828 if (wl->fwlog_size < 0) {
4829 mutex_unlock(&wl->mutex);
4830 return 0;
4831 }
4832
4833 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4834 len = min(count, (size_t)wl->fwlog_size);
4835 wl->fwlog_size -= len;
4836 memcpy(buffer, wl->fwlog, len);
4837
4838 /* Make room for new messages */
4839 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4840
4841 mutex_unlock(&wl->mutex);
4842
4843 return len;
4844}
4845
4846static struct bin_attribute fwlog_attr = {
4847 .attr = {.name = "fwlog", .mode = S_IRUSR},
4848 .read = wl1271_sysfs_read_fwlog,
4849};
4850
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004851int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004852{
4853 int ret;
4854
4855 if (wl->mac80211_registered)
4856 return 0;
4857
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004858 ret = wl1271_fetch_nvs(wl);
4859 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004860 /* NOTE: The wl->nvs->nvs element must be first, in
4861 * order to simplify the casting, we assume it is at
4862 * the beginning of the wl->nvs structure.
4863 */
4864 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004865
4866 wl->mac_addr[0] = nvs_ptr[11];
4867 wl->mac_addr[1] = nvs_ptr[10];
4868 wl->mac_addr[2] = nvs_ptr[6];
4869 wl->mac_addr[3] = nvs_ptr[5];
4870 wl->mac_addr[4] = nvs_ptr[4];
4871 wl->mac_addr[5] = nvs_ptr[3];
4872 }
4873
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004874 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4875
4876 ret = ieee80211_register_hw(wl->hw);
4877 if (ret < 0) {
4878 wl1271_error("unable to register mac80211 hw: %d", ret);
4879 return ret;
4880 }
4881
4882 wl->mac80211_registered = true;
4883
Eliad Pellerd60080a2010-11-24 12:53:16 +02004884 wl1271_debugfs_init(wl);
4885
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004886 register_netdevice_notifier(&wl1271_dev_notifier);
4887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004888 wl1271_notice("loaded");
4889
4890 return 0;
4891}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004892EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004893
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004894void wl1271_unregister_hw(struct wl1271 *wl)
4895{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004896 if (wl->state == WL1271_STATE_PLT)
4897 __wl1271_plt_stop(wl);
4898
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004899 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004900 ieee80211_unregister_hw(wl->hw);
4901 wl->mac80211_registered = false;
4902
4903}
4904EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4905
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004906int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004907{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004908 static const u32 cipher_suites[] = {
4909 WLAN_CIPHER_SUITE_WEP40,
4910 WLAN_CIPHER_SUITE_WEP104,
4911 WLAN_CIPHER_SUITE_TKIP,
4912 WLAN_CIPHER_SUITE_CCMP,
4913 WL1271_CIPHER_SUITE_GEM,
4914 };
4915
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004916 /* The tx descriptor buffer and the TKIP space. */
4917 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4918 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004919
4920 /* unit us */
4921 /* FIXME: find a proper value */
4922 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004923 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004924
4925 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004926 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004927 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004928 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004929 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004930 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004931 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004932 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004933 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004934 IEEE80211_HW_AP_LINK_PS |
4935 IEEE80211_HW_AMPDU_AGGREGATION |
4936 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004937
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004938 wl->hw->wiphy->cipher_suites = cipher_suites;
4939 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4940
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004941 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004942 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4943 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004944 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004945 wl->hw->wiphy->max_sched_scan_ssids = 16;
4946 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004947 /*
4948 * Maximum length of elements in scanning probe request templates
4949 * should be the maximum length possible for a template, without
4950 * the IEEE80211 header of the template
4951 */
Eliad Peller154037d2011-08-14 13:17:12 +03004952 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004953 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004954
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004955 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4956 sizeof(struct ieee80211_header);
4957
Eliad Peller1ec23f72011-08-25 14:26:54 +03004958 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4959
Luciano Coelho4a31c112011-03-21 23:16:14 +02004960 /* make sure all our channels fit in the scanned_ch bitmask */
4961 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4962 ARRAY_SIZE(wl1271_channels_5ghz) >
4963 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004964 /*
4965 * We keep local copies of the band structs because we need to
4966 * modify them on a per-device basis.
4967 */
4968 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4969 sizeof(wl1271_band_2ghz));
4970 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4971 sizeof(wl1271_band_5ghz));
4972
4973 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4974 &wl->bands[IEEE80211_BAND_2GHZ];
4975 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4976 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004977
Kalle Valo12bd8942010-03-18 12:26:33 +02004978 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004979 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004980
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004981 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4982
Felipe Balbia390e852011-10-06 10:07:44 +03004983 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004984
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004985 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004986 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004987
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004988 wl->hw->max_rx_aggregation_subframes = 8;
4989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990 return 0;
4991}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004992EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004995
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004996struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004997{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004998 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004999 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005001 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005002 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005004 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005006 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5007 if (!hw) {
5008 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005009 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005010 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005011 }
5012
Julia Lawall929ebd32010-05-15 23:16:39 +02005013 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005014 if (!plat_dev) {
5015 wl1271_error("could not allocate platform_device");
5016 ret = -ENOMEM;
5017 goto err_plat_alloc;
5018 }
5019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005020 wl = hw->priv;
5021 memset(wl, 0, sizeof(*wl));
5022
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005023 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02005024 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005026 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005027 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005028
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005029 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005030 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005031 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5032
Ido Yariva6208652011-03-01 15:14:41 +02005033 skb_queue_head_init(&wl->deferred_rx_queue);
5034 skb_queue_head_init(&wl->deferred_tx_queue);
5035
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005036 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005037 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005038 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5039 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5040 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005041
Eliad Peller92ef8962011-06-07 12:50:46 +03005042 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5043 if (!wl->freezable_wq) {
5044 ret = -ENOMEM;
5045 goto err_hw;
5046 }
5047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005048 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005049 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005050 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005051 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005052 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005053 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005054 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005055 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005056 wl->ap_ps_map = 0;
5057 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005058 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005059 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005060 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005061 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005062 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005063 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005064 wl->fwlog_size = 0;
5065 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005066
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005067 /* The system link is always allocated */
5068 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5069
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005070 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005071 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005072 wl->tx_frames[i] = NULL;
5073
5074 spin_lock_init(&wl->wl_lock);
5075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005076 wl->state = WL1271_STATE_OFF;
5077 mutex_init(&wl->mutex);
5078
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005079 /* Apply default driver configuration. */
5080 wl1271_conf_init(wl);
5081
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005082 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5083 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5084 if (!wl->aggr_buf) {
5085 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005086 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005087 }
5088
Ido Yariv990f5de2011-03-31 10:06:59 +02005089 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5090 if (!wl->dummy_packet) {
5091 ret = -ENOMEM;
5092 goto err_aggr;
5093 }
5094
Ido Yariv95dac04f2011-06-06 14:57:06 +03005095 /* Allocate one page for the FW log */
5096 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5097 if (!wl->fwlog) {
5098 ret = -ENOMEM;
5099 goto err_dummy_packet;
5100 }
5101
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005102 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005103 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005104 if (ret) {
5105 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03005106 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005107 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005108 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005109
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005110 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005111 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005112 if (ret < 0) {
5113 wl1271_error("failed to create sysfs file bt_coex_state");
5114 goto err_platform;
5115 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005116
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005117 /* Create sysfs file to get HW PG version */
5118 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5119 if (ret < 0) {
5120 wl1271_error("failed to create sysfs file hw_pg_ver");
5121 goto err_bt_coex_state;
5122 }
5123
Ido Yariv95dac04f2011-06-06 14:57:06 +03005124 /* Create sysfs file for the FW log */
5125 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
5126 if (ret < 0) {
5127 wl1271_error("failed to create sysfs file fwlog");
5128 goto err_hw_pg_ver;
5129 }
5130
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005131 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005132
Ido Yariv95dac04f2011-06-06 14:57:06 +03005133err_hw_pg_ver:
5134 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5135
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005136err_bt_coex_state:
5137 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
5138
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005139err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005140 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005141
Ido Yariv95dac04f2011-06-06 14:57:06 +03005142err_fwlog:
5143 free_page((unsigned long)wl->fwlog);
5144
Ido Yariv990f5de2011-03-31 10:06:59 +02005145err_dummy_packet:
5146 dev_kfree_skb(wl->dummy_packet);
5147
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005148err_aggr:
5149 free_pages((unsigned long)wl->aggr_buf, order);
5150
Eliad Peller92ef8962011-06-07 12:50:46 +03005151err_wq:
5152 destroy_workqueue(wl->freezable_wq);
5153
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005154err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005155 wl1271_debugfs_exit(wl);
5156 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005157
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005158err_plat_alloc:
5159 ieee80211_free_hw(hw);
5160
5161err_hw_alloc:
5162
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005163 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005164}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005165EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005166
5167int wl1271_free_hw(struct wl1271 *wl)
5168{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005169 /* Unblock any fwlog readers */
5170 mutex_lock(&wl->mutex);
5171 wl->fwlog_size = -1;
5172 wake_up_interruptible_all(&wl->fwlog_waitq);
5173 mutex_unlock(&wl->mutex);
5174
5175 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005176
5177 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5178
5179 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005180 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005181 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005182 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005183 free_pages((unsigned long)wl->aggr_buf,
5184 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005185 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005186
5187 wl1271_debugfs_exit(wl);
5188
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005189 vfree(wl->fw);
5190 wl->fw = NULL;
5191 kfree(wl->nvs);
5192 wl->nvs = NULL;
5193
5194 kfree(wl->fw_status);
5195 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005196 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005197
5198 ieee80211_free_hw(wl->hw);
5199
5200 return 0;
5201}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005202EXPORT_SYMBOL_GPL(wl1271_free_hw);
5203
Felipe Balbia390e852011-10-06 10:07:44 +03005204static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5205{
5206 struct wl1271 *wl = cookie;
5207 unsigned long flags;
5208
5209 wl1271_debug(DEBUG_IRQ, "IRQ");
5210
5211 /* complete the ELP completion */
5212 spin_lock_irqsave(&wl->wl_lock, flags);
5213 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5214 if (wl->elp_compl) {
5215 complete(wl->elp_compl);
5216 wl->elp_compl = NULL;
5217 }
5218
5219 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5220 /* don't enqueue a work right now. mark it as pending */
5221 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5222 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5223 disable_irq_nosync(wl->irq);
5224 pm_wakeup_event(wl->dev, 0);
5225 spin_unlock_irqrestore(&wl->wl_lock, flags);
5226 return IRQ_HANDLED;
5227 }
5228 spin_unlock_irqrestore(&wl->wl_lock, flags);
5229
5230 return IRQ_WAKE_THREAD;
5231}
5232
Felipe Balbice2a2172011-10-05 14:12:55 +03005233static int __devinit wl12xx_probe(struct platform_device *pdev)
5234{
Felipe Balbia390e852011-10-06 10:07:44 +03005235 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5236 struct ieee80211_hw *hw;
5237 struct wl1271 *wl;
5238 unsigned long irqflags;
5239 int ret = -ENODEV;
5240
5241 hw = wl1271_alloc_hw();
5242 if (IS_ERR(hw)) {
5243 wl1271_error("can't allocate hw");
5244 ret = PTR_ERR(hw);
5245 goto out;
5246 }
5247
5248 wl = hw->priv;
5249 wl->irq = platform_get_irq(pdev, 0);
5250 wl->ref_clock = pdata->board_ref_clock;
5251 wl->tcxo_clock = pdata->board_tcxo_clock;
5252 wl->platform_quirks = pdata->platform_quirks;
5253 wl->set_power = pdata->set_power;
5254 wl->dev = &pdev->dev;
5255 wl->if_ops = pdata->ops;
5256
5257 platform_set_drvdata(pdev, wl);
5258
5259 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5260 irqflags = IRQF_TRIGGER_RISING;
5261 else
5262 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5263
5264 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5265 irqflags,
5266 pdev->name, wl);
5267 if (ret < 0) {
5268 wl1271_error("request_irq() failed: %d", ret);
5269 goto out_free_hw;
5270 }
5271
5272 ret = enable_irq_wake(wl->irq);
5273 if (!ret) {
5274 wl->irq_wake_enabled = true;
5275 device_init_wakeup(wl->dev, 1);
5276 if (pdata->pwr_in_suspend)
5277 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5278
5279 }
5280 disable_irq(wl->irq);
5281
5282 ret = wl1271_init_ieee80211(wl);
5283 if (ret)
5284 goto out_irq;
5285
5286 ret = wl1271_register_hw(wl);
5287 if (ret)
5288 goto out_irq;
5289
Felipe Balbice2a2172011-10-05 14:12:55 +03005290 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005291
5292out_irq:
5293 free_irq(wl->irq, wl);
5294
5295out_free_hw:
5296 wl1271_free_hw(wl);
5297
5298out:
5299 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005300}
5301
5302static int __devexit wl12xx_remove(struct platform_device *pdev)
5303{
Felipe Balbia390e852011-10-06 10:07:44 +03005304 struct wl1271 *wl = platform_get_drvdata(pdev);
5305
5306 if (wl->irq_wake_enabled) {
5307 device_init_wakeup(wl->dev, 0);
5308 disable_irq_wake(wl->irq);
5309 }
5310 wl1271_unregister_hw(wl);
5311 free_irq(wl->irq, wl);
5312 wl1271_free_hw(wl);
5313
Felipe Balbice2a2172011-10-05 14:12:55 +03005314 return 0;
5315}
5316
5317static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
5318 { "wl12xx-sdio", 0 },
5319 { "wl12xx-spi", 0 },
5320 { } /* Terminating Entry */
5321};
5322MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5323
5324static struct platform_driver wl12xx_driver = {
5325 .probe = wl12xx_probe,
5326 .remove = __devexit_p(wl12xx_remove),
5327 .id_table = wl12xx_id_table,
5328 .driver = {
5329 .name = "wl12xx",
5330 .owner = THIS_MODULE,
5331 }
5332};
5333
5334static int __init wl12xx_init(void)
5335{
5336 return platform_driver_register(&wl12xx_driver);
5337}
5338module_init(wl12xx_init);
5339
5340static void __exit wl12xx_exit(void)
5341{
5342 platform_driver_unregister(&wl12xx_driver);
5343}
5344module_exit(wl12xx_exit);
5345
Guy Eilam491bbd62011-01-12 10:33:29 +01005346u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005347EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005348module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005349MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5350
Ido Yariv95dac04f2011-06-06 14:57:06 +03005351module_param_named(fwlog, fwlog_param, charp, 0);
5352MODULE_PARM_DESC(keymap,
5353 "FW logger options: continuous, ondemand, dbgpins or disable");
5354
Eliad Peller2a5bff02011-08-25 18:10:59 +03005355module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5356MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5357
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005358MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005359MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005360MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");