blob: 56927051f665fa03733918a5513fe39ebe2dc849 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000039#include "reg.h"
40#include "io.h"
41#include "event.h"
42#include "tx.h"
43#include "rx.h"
44#include "ps.h"
45#include "init.h"
46#include "debugfs.h"
47#include "cmd.h"
48#include "boot.h"
49#include "testmode.h"
50#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030051
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020052#define WL1271_BOOT_RETRIES 3
53
Juuso Oikarinen8a080482009-10-13 12:47:44 +030054static struct conf_drv_settings default_conf = {
55 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030056 .params = {
57 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
58 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
59 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
62 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
63 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
65 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
79 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
80 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
83 /* active scan params */
84 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
87 /* passive scan params */
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
91 /* passive scan in dual antenna params */
92 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
95 /* general params */
96 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
97 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
98 [CONF_SG_BEACON_MISS_PERCENT] = 60,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_RXT] = 1200,
101 [CONF_SG_TXT] = 1000,
102 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
103 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
104 [CONF_SG_HV3_MAX_SERVED] = 6,
105 [CONF_SG_PS_POLL_TIMEOUT] = 10,
106 [CONF_SG_UPSD_TIMEOUT] = 10,
107 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
108 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
109 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
110 /* AP params */
111 [CONF_AP_BEACON_MISS_TX] = 3,
112 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
113 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
114 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
115 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
116 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300117 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200118 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300119 },
120 .rx = {
121 .rx_msdu_life_time = 512000,
122 .packet_detection_threshold = 0,
123 .ps_poll_timeout = 15,
124 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300125 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200126 .rx_cca_threshold = 0,
127 .irq_blk_threshold = 0xFFFF,
128 .irq_pkt_threshold = 0,
129 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300130 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
131 },
132 .tx = {
133 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200134 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300135 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300136 .short_retry_limit = 10,
137 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200138 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300139 },
140 .ac_conf_count = 4,
141 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200142 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300143 .ac = CONF_TX_AC_BE,
144 .cw_min = 15,
145 .cw_max = 63,
146 .aifsn = 3,
147 .tx_op_limit = 0,
148 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200149 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300150 .ac = CONF_TX_AC_BK,
151 .cw_min = 15,
152 .cw_max = 63,
153 .aifsn = 7,
154 .tx_op_limit = 0,
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .ac = CONF_TX_AC_VI,
158 .cw_min = 15,
159 .cw_max = 63,
160 .aifsn = CONF_TX_AIFS_PIFS,
161 .tx_op_limit = 3008,
162 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200163 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300164 .ac = CONF_TX_AC_VO,
165 .cw_min = 15,
166 .cw_max = 63,
167 .aifsn = CONF_TX_AIFS_PIFS,
168 .tx_op_limit = 1504,
169 },
170 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300171 .max_tx_retries = 100,
172 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200173 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300174 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200175 [CONF_TX_AC_BE] = {
176 .queue_id = CONF_TX_AC_BE,
177 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .tsid = CONF_TX_AC_BE,
179 .ps_scheme = CONF_PS_SCHEME_LEGACY,
180 .ack_policy = CONF_ACK_POLICY_LEGACY,
181 .apsd_conf = {0, 0},
182 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BK] = {
184 .queue_id = CONF_TX_AC_BK,
185 .channel_type = CONF_CHANNEL_TYPE_EDCF,
186 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300187 .ps_scheme = CONF_PS_SCHEME_LEGACY,
188 .ack_policy = CONF_ACK_POLICY_LEGACY,
189 .apsd_conf = {0, 0},
190 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200191 [CONF_TX_AC_VI] = {
192 .queue_id = CONF_TX_AC_VI,
193 .channel_type = CONF_CHANNEL_TYPE_EDCF,
194 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300195 .ps_scheme = CONF_PS_SCHEME_LEGACY,
196 .ack_policy = CONF_ACK_POLICY_LEGACY,
197 .apsd_conf = {0, 0},
198 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200199 [CONF_TX_AC_VO] = {
200 .queue_id = CONF_TX_AC_VO,
201 .channel_type = CONF_CHANNEL_TYPE_EDCF,
202 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300203 .ps_scheme = CONF_PS_SCHEME_LEGACY,
204 .ack_policy = CONF_ACK_POLICY_LEGACY,
205 .apsd_conf = {0, 0},
206 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300207 },
208 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200209 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300210 .tx_compl_threshold = 4,
211 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
212 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200213 .tmpl_short_retry_limit = 10,
214 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300215 },
216 .conn = {
217 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300218 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300220 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300221 .bcn_filt_ie = {
222 [0] = {
223 .ie = WLAN_EID_CHANNEL_SWITCH,
224 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300225 },
226 [1] = {
227 .ie = WLAN_EID_HT_INFORMATION,
228 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
229 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300236 .ps_poll_threshold = 10,
237 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300238 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200239 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300240 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300241 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200242 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300243 .keep_alive_interval = 55000,
244 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200246 .itrim = {
247 .enable = false,
248 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200249 },
250 .pm_config = {
251 .host_clk_settling_time = 5000,
252 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300253 },
254 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100259 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200260 },
261 .scan = {
262 .min_dwell_time_active = 7500,
263 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100264 .min_dwell_time_passive = 100000,
265 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200266 .num_probe_reqs = 2,
267 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300268 .sched_scan = {
269 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300270 .min_dwell_time_active = 30,
271 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300272 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300273 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300274 .num_probe_reqs = 2,
275 .rssi_threshold = -90,
276 .snr_threshold = 0,
277 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200278 .rf = {
279 .tx_per_channel_power_compensation_2 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 },
282 .tx_per_channel_power_compensation_5 = {
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 },
287 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100288 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300289 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100290 .tx_ba_win_size = 64,
291 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300292 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100293 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200294 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200295 .num_stations = 1,
296 .ssid_profiles = 1,
297 .rx_block_num = 70,
298 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300299 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200300 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .min_req_rx_blocks = 22,
302 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 },
304 .mem_wl128x = {
305 .num_stations = 1,
306 .ssid_profiles = 1,
307 .rx_block_num = 40,
308 .tx_min_block_num = 40,
309 .dynamic_memory = 1,
310 .min_req_tx_blocks = 45,
311 .min_req_rx_blocks = 22,
312 .tx_min = 27,
313 },
Shahar Leviff868432011-04-11 15:41:46 +0300314 .fm_coex = {
315 .enable = true,
316 .swallow_period = 5,
317 .n_divider_fref_set_1 = 0xff, /* default */
318 .n_divider_fref_set_2 = 12,
319 .m_divider_fref_set_1 = 148,
320 .m_divider_fref_set_2 = 0xffff, /* default */
321 .coex_pll_stabilization_time = 0xffffffff, /* default */
322 .ldo_stabilization_time = 0xffff, /* default */
323 .fm_disturbed_band_margin = 0xff, /* default */
324 .swallow_clk_diff = 0xff, /* default */
325 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300326 .rx_streaming = {
327 .duration = 150,
328 .queues = 0x1,
329 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300330 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300331 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300332 .fwlog = {
333 .mode = WL12XX_FWLOG_ON_DEMAND,
334 .mem_blocks = 2,
335 .severity = 0,
336 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
337 .output = WL12XX_FWLOG_OUTPUT_HOST,
338 .threshold = 0,
339 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300340 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300341 .rate = {
342 .rate_retry_score = 32000,
343 .per_add = 8192,
344 .per_th1 = 2048,
345 .per_th2 = 4096,
346 .max_per = 8100,
347 .inverse_curiosity_factor = 5,
348 .tx_fail_low_th = 4,
349 .tx_fail_high_th = 10,
350 .per_alpha_shift = 4,
351 .per_add_shift = 13,
352 .per_beta1_shift = 10,
353 .per_beta2_shift = 8,
354 .rate_check_up = 2,
355 .rate_check_down = 12,
356 .rate_retry_policy = {
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00,
360 },
361 },
Eliad Peller94877752011-08-28 15:11:56 +0300362 .hangover = {
363 .recover_time = 0,
364 .hangover_period = 20,
365 .dynamic_mode = 1,
366 .early_termination_mode = 1,
367 .max_period = 20,
368 .min_period = 1,
369 .increase_delta = 1,
370 .decrease_delta = 2,
371 .quiet_time = 4,
372 .increase_time = 1,
373 .window_size = 16,
374 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300375};
376
Ido Yariv95dac04f2011-06-06 14:57:06 +0300377static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300378static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300379
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300380static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200381 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300382 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200383static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200384static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200385
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 Pellerba8447f2011-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 Pellerba8447f2011-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 Pellerba8447f2011-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 Pellerba8447f2011-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 Pellerba8447f2011-10-10 10:13:00 +0200476 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477
Eliad Pellerba8447f2011-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 Pellerba8447f2011-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 Pellerba8447f2011-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
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300934static irqreturn_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 Yarivbaacb9a2011-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}
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057static int wl1271_fetch_firmware(struct wl1271 *wl)
1058{
1059 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001060 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 int ret;
1062
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001063 if (wl->chip.id == CHIP_ID_1283_PG20)
1064 fw_name = WL128X_FW_NAME;
1065 else
1066 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001067
1068 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1069
Felipe Balbia390e852011-10-06 10:07:44 +03001070 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071
1072 if (ret < 0) {
1073 wl1271_error("could not get firmware: %d", ret);
1074 return ret;
1075 }
1076
1077 if (fw->size % 4) {
1078 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1079 fw->size);
1080 ret = -EILSEQ;
1081 goto out;
1082 }
1083
Arik Nemtsov166d5042010-10-16 21:44:57 +02001084 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001086 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
1088 if (!wl->fw) {
1089 wl1271_error("could not allocate memory for the firmware");
1090 ret = -ENOMEM;
1091 goto out;
1092 }
1093
1094 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 ret = 0;
1096
1097out:
1098 release_firmware(fw);
1099
1100 return ret;
1101}
1102
1103static int wl1271_fetch_nvs(struct wl1271 *wl)
1104{
1105 const struct firmware *fw;
1106 int ret;
1107
Felipe Balbia390e852011-10-06 10:07:44 +03001108 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109
1110 if (ret < 0) {
1111 wl1271_error("could not get nvs file: %d", ret);
1112 return ret;
1113 }
1114
Shahar Levibc765bf2011-03-06 16:32:10 +02001115 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116
1117 if (!wl->nvs) {
1118 wl1271_error("could not allocate memory for the nvs file");
1119 ret = -ENOMEM;
1120 goto out;
1121 }
1122
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001123 wl->nvs_len = fw->size;
1124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125out:
1126 release_firmware(fw);
1127
1128 return ret;
1129}
1130
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001131void wl12xx_queue_recovery_work(struct wl1271 *wl)
1132{
1133 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1134 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1135}
1136
Ido Yariv95dac04f2011-06-06 14:57:06 +03001137size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1138{
1139 size_t len = 0;
1140
1141 /* The FW log is a length-value list, find where the log end */
1142 while (len < maxlen) {
1143 if (memblock[len] == 0)
1144 break;
1145 if (len + memblock[len] + 1 > maxlen)
1146 break;
1147 len += memblock[len] + 1;
1148 }
1149
1150 /* Make sure we have enough room */
1151 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1152
1153 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1154 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1155 wl->fwlog_size += len;
1156
1157 return len;
1158}
1159
1160static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1161{
1162 u32 addr;
1163 u32 first_addr;
1164 u8 *block;
1165
1166 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1167 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1168 (wl->conf.fwlog.mem_blocks == 0))
1169 return;
1170
1171 wl1271_info("Reading FW panic log");
1172
1173 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1174 if (!block)
1175 return;
1176
1177 /*
1178 * Make sure the chip is awake and the logger isn't active.
1179 * This might fail if the firmware hanged.
1180 */
1181 if (!wl1271_ps_elp_wakeup(wl))
1182 wl12xx_cmd_stop_fwlog(wl);
1183
1184 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001185 wl12xx_fw_status(wl, wl->fw_status);
1186 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001187 if (!first_addr)
1188 goto out;
1189
1190 /* Traverse the memory blocks linked list */
1191 addr = first_addr;
1192 do {
1193 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1194 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1195 false);
1196
1197 /*
1198 * Memory blocks are linked to one another. The first 4 bytes
1199 * of each memory block hold the hardware address of the next
1200 * one. The last memory block points to the first one.
1201 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001202 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001203 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1204 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1205 break;
1206 } while (addr && (addr != first_addr));
1207
1208 wake_up_interruptible(&wl->fwlog_waitq);
1209
1210out:
1211 kfree(block);
1212}
1213
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001214static void wl1271_recovery_work(struct work_struct *work)
1215{
1216 struct wl1271 *wl =
1217 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001218 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001219 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001220
1221 mutex_lock(&wl->mutex);
1222
1223 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001224 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001225
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001226 /* Avoid a recursive recovery */
1227 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1228
Ido Yariv95dac04f2011-06-06 14:57:06 +03001229 wl12xx_read_fwlog_panic(wl);
1230
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001231 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1232 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001233
Eliad Peller2a5bff02011-08-25 18:10:59 +03001234 BUG_ON(bug_on_recovery);
1235
Oz Krakowskib992c682011-06-26 10:36:02 +03001236 /*
1237 * Advance security sequence number to overcome potential progress
1238 * in the firmware during recovery. This doens't hurt if the network is
1239 * not encrypted.
1240 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001241 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001242 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001243 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001244 wlvif->tx_security_seq +=
1245 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1246 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001247
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001248 /* Prevent spurious TX during FW restart */
1249 ieee80211_stop_queues(wl->hw);
1250
Luciano Coelho33c2c062011-05-10 14:46:02 +03001251 if (wl->sched_scanning) {
1252 ieee80211_sched_scan_stopped(wl->hw);
1253 wl->sched_scanning = false;
1254 }
1255
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001257 while (!list_empty(&wl->wlvif_list)) {
1258 wlvif = list_first_entry(&wl->wlvif_list,
1259 struct wl12xx_vif, list);
1260 vif = wl12xx_wlvif_to_vif(wlvif);
1261 __wl1271_op_remove_interface(wl, vif, false);
1262 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001263 mutex_unlock(&wl->mutex);
1264 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001265
1266 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1267
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001268 ieee80211_restart_hw(wl->hw);
1269
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001270 /*
1271 * Its safe to enable TX now - the queues are stopped after a request
1272 * to restart the HW.
1273 */
1274 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001275 return;
1276out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001277 mutex_unlock(&wl->mutex);
1278}
1279
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280static void wl1271_fw_wakeup(struct wl1271 *wl)
1281{
1282 u32 elp_reg;
1283
1284 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001285 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286}
1287
1288static int wl1271_setup(struct wl1271 *wl)
1289{
1290 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1291 if (!wl->fw_status)
1292 return -ENOMEM;
1293
1294 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1295 if (!wl->tx_res_if) {
1296 kfree(wl->fw_status);
1297 return -ENOMEM;
1298 }
1299
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300 return 0;
1301}
1302
1303static int wl1271_chip_wakeup(struct wl1271 *wl)
1304{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001305 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 int ret = 0;
1307
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001308 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001309 ret = wl1271_power_on(wl);
1310 if (ret < 0)
1311 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001313 wl1271_io_reset(wl);
1314 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* We don't need a real memory partition here, because we only want
1317 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001318 memset(&partition, 0, sizeof(partition));
1319 partition.reg.start = REGISTERS_BASE;
1320 partition.reg.size = REGISTERS_DOWN_SIZE;
1321 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322
1323 /* ELP module wake up */
1324 wl1271_fw_wakeup(wl);
1325
1326 /* whal_FwCtrl_BootSm() */
1327
1328 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001329 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330
1331 /* 1. check if chip id is valid */
1332
1333 switch (wl->chip.id) {
1334 case CHIP_ID_1271_PG10:
1335 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1336 wl->chip.id);
1337
1338 ret = wl1271_setup(wl);
1339 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001340 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 break;
1342 case CHIP_ID_1271_PG20:
1343 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1344 wl->chip.id);
1345
1346 ret = wl1271_setup(wl);
1347 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001348 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001350 case CHIP_ID_1283_PG20:
1351 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1352 wl->chip.id);
1353
1354 ret = wl1271_setup(wl);
1355 if (ret < 0)
1356 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001357
Ido Yariv0da13da2011-03-31 10:06:58 +02001358 if (wl1271_set_block_size(wl))
1359 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001360 break;
1361 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001365 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366 }
1367
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001368 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 ret = wl1271_fetch_firmware(wl);
1370 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 }
1373
1374 /* No NVS from netlink, try to get it from the filesystem */
1375 if (wl->nvs == NULL) {
1376 ret = wl1271_fetch_nvs(wl);
1377 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001378 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379 }
1380
1381out:
1382 return ret;
1383}
1384
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385int wl1271_plt_start(struct wl1271 *wl)
1386{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001388 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 int ret;
1390
1391 mutex_lock(&wl->mutex);
1392
1393 wl1271_notice("power up");
1394
1395 if (wl->state != WL1271_STATE_OFF) {
1396 wl1271_error("cannot go into PLT state because not "
1397 "in off state: %d", wl->state);
1398 ret = -EBUSY;
1399 goto out;
1400 }
1401
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001402 while (retries) {
1403 retries--;
1404 ret = wl1271_chip_wakeup(wl);
1405 if (ret < 0)
1406 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 ret = wl1271_boot(wl);
1409 if (ret < 0)
1410 goto power_off;
1411
1412 ret = wl1271_plt_init(wl);
1413 if (ret < 0)
1414 goto irq_disable;
1415
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001416 wl->state = WL1271_STATE_PLT;
1417 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001418 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001419
Gery Kahn6f07b722011-07-18 14:21:49 +03001420 /* update hw/fw version info in wiphy struct */
1421 wiphy->hw_version = wl->chip.id;
1422 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1423 sizeof(wiphy->fw_version));
1424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 goto out;
1426
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001427irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001428 mutex_unlock(&wl->mutex);
1429 /* Unlocking the mutex in the middle of handling is
1430 inherently unsafe. In this case we deem it safe to do,
1431 because we need to let any possibly pending IRQ out of
1432 the system (and while we are WL1271_STATE_OFF the IRQ
1433 work function will not do anything.) Also, any other
1434 possible concurrent operations will fail due to the
1435 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001436 wl1271_disable_interrupts(wl);
1437 wl1271_flush_deferred_work(wl);
1438 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 mutex_lock(&wl->mutex);
1440power_off:
1441 wl1271_power_off(wl);
1442 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001444 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1445 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446out:
1447 mutex_unlock(&wl->mutex);
1448
1449 return ret;
1450}
1451
Luciano Coelho4623ec72011-03-21 19:26:41 +02001452static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453{
1454 int ret = 0;
1455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 wl1271_notice("power down");
1457
1458 if (wl->state != WL1271_STATE_PLT) {
1459 wl1271_error("cannot power down because not in PLT "
1460 "state: %d", wl->state);
1461 ret = -EBUSY;
1462 goto out;
1463 }
1464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 wl1271_power_off(wl);
1466
1467 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001468 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001471 wl1271_disable_interrupts(wl);
1472 wl1271_flush_deferred_work(wl);
1473 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001474 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475 mutex_lock(&wl->mutex);
1476out:
1477 return ret;
1478}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001479
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001480int wl1271_plt_stop(struct wl1271 *wl)
1481{
1482 int ret;
1483
1484 mutex_lock(&wl->mutex);
1485 ret = __wl1271_plt_stop(wl);
1486 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 return ret;
1488}
1489
Johannes Berg7bb45682011-02-24 14:42:06 +01001490static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491{
1492 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001493 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1494 struct ieee80211_vif *vif = info->control.vif;
1495 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001496 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001497 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001498 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001500 mapping = skb_get_queue_mapping(skb);
1501 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001502
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001503 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001504
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001505 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001506
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001507 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001508 if (hlid == WL12XX_INVALID_LINK_ID ||
1509 !test_bit(hlid, wlvif->links_map)) {
1510 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1511 dev_kfree_skb(skb);
1512 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001513 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001515 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1516 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1517
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001518 wl->tx_queue_count[q]++;
1519
1520 /*
1521 * The workqueue is slow to process the tx_queue and we need stop
1522 * the queue here, otherwise the queue will get too long.
1523 */
1524 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1525 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1526 ieee80211_stop_queue(wl->hw, mapping);
1527 set_bit(q, &wl->stopped_queues_map);
1528 }
1529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 /*
1531 * The chip specific setup must run before the first TX packet -
1532 * before that, the tx_work will not be initialized!
1533 */
1534
Ido Yarivb07d4032011-03-01 15:14:43 +02001535 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1536 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001537 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001538
Arik Nemtsov04216da2011-08-14 13:17:38 +03001539out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001540 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541}
1542
Shahar Leviae47c452011-03-06 16:32:14 +02001543int wl1271_tx_dummy_packet(struct wl1271 *wl)
1544{
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001546 int q;
1547
1548 /* no need to queue a new dummy packet if one is already pending */
1549 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1550 return 0;
1551
1552 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 spin_lock_irqsave(&wl->wl_lock, flags);
1555 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001556 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001557 spin_unlock_irqrestore(&wl->wl_lock, flags);
1558
1559 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1560 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001561 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001562
1563 /*
1564 * If the FW TX is busy, TX work will be scheduled by the threaded
1565 * interrupt handler function
1566 */
1567 return 0;
1568}
1569
1570/*
1571 * The size of the dummy packet should be at least 1400 bytes. However, in
1572 * order to minimize the number of bus transactions, aligning it to 512 bytes
1573 * boundaries could be beneficial, performance wise
1574 */
1575#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1576
Luciano Coelhocf27d862011-04-01 21:08:23 +03001577static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001578{
1579 struct sk_buff *skb;
1580 struct ieee80211_hdr_3addr *hdr;
1581 unsigned int dummy_packet_size;
1582
1583 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1584 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1585
1586 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001587 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 wl1271_warning("Failed to allocate a dummy packet skb");
1589 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001590 }
1591
1592 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1593
1594 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1595 memset(hdr, 0, sizeof(*hdr));
1596 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 IEEE80211_STYPE_NULLFUNC |
1598 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001599
Ido Yariv990f5de2011-03-31 10:06:59 +02001600 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001601
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001602 /* Dummy packets require the TID to be management */
1603 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001604
1605 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001606 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001607 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001608
Ido Yariv990f5de2011-03-31 10:06:59 +02001609 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001610}
1611
Ido Yariv990f5de2011-03-31 10:06:59 +02001612
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001613static struct notifier_block wl1271_dev_notifier = {
1614 .notifier_call = wl1271_dev_notify,
1615};
1616
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001617#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001618static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1619 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001620{
Eliad Pellere85d1622011-06-27 13:06:43 +03001621 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001622
Eliad Peller94390642011-05-13 11:57:13 +03001623 mutex_lock(&wl->mutex);
1624
Eliad Pellerba8447f2011-10-10 10:13:00 +02001625 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001626 goto out_unlock;
1627
Eliad Peller94390642011-05-13 11:57:13 +03001628 ret = wl1271_ps_elp_wakeup(wl);
1629 if (ret < 0)
1630 goto out_unlock;
1631
1632 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001633 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001634 DECLARE_COMPLETION_ONSTACK(compl);
1635
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001636 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001637 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001638 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001639 if (ret < 0)
1640 goto out_sleep;
1641
1642 /* we must unlock here so we will be able to get events */
1643 wl1271_ps_elp_sleep(wl);
1644 mutex_unlock(&wl->mutex);
1645
1646 ret = wait_for_completion_timeout(
1647 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1648 if (ret <= 0) {
1649 wl1271_warning("couldn't enter ps mode!");
1650 ret = -EBUSY;
1651 goto out;
1652 }
1653
1654 /* take mutex again, and wakeup */
1655 mutex_lock(&wl->mutex);
1656
1657 ret = wl1271_ps_elp_wakeup(wl);
1658 if (ret < 0)
1659 goto out_unlock;
1660 }
1661out_sleep:
1662 wl1271_ps_elp_sleep(wl);
1663out_unlock:
1664 mutex_unlock(&wl->mutex);
1665out:
1666 return ret;
1667
1668}
1669
Eliad Peller0603d892011-10-05 11:55:51 +02001670static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1671 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001672{
Eliad Pellere85d1622011-06-27 13:06:43 +03001673 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001674
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001675 mutex_lock(&wl->mutex);
1676
Eliad Peller53d40d02011-10-10 10:13:02 +02001677 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001678 goto out_unlock;
1679
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680 ret = wl1271_ps_elp_wakeup(wl);
1681 if (ret < 0)
1682 goto out_unlock;
1683
Eliad Peller0603d892011-10-05 11:55:51 +02001684 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001685
1686 wl1271_ps_elp_sleep(wl);
1687out_unlock:
1688 mutex_unlock(&wl->mutex);
1689 return ret;
1690
1691}
1692
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001693static int wl1271_configure_suspend(struct wl1271 *wl,
1694 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001695{
Eliad Peller536129c2011-10-05 11:55:45 +02001696 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001697 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001698 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001699 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001700 return 0;
1701}
1702
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001703static void wl1271_configure_resume(struct wl1271 *wl,
1704 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001705{
1706 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001707 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1708 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001709
1710 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001711 return;
1712
1713 mutex_lock(&wl->mutex);
1714 ret = wl1271_ps_elp_wakeup(wl);
1715 if (ret < 0)
1716 goto out;
1717
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001718 if (is_sta) {
1719 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001720 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001721 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001722 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001723 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001724 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001725 }
Eliad Peller94390642011-05-13 11:57:13 +03001726
1727 wl1271_ps_elp_sleep(wl);
1728out:
1729 mutex_unlock(&wl->mutex);
1730}
1731
Eliad Peller402e48612011-05-13 11:57:09 +03001732static int wl1271_op_suspend(struct ieee80211_hw *hw,
1733 struct cfg80211_wowlan *wow)
1734{
1735 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001736 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 int ret;
1738
Eliad Peller402e48612011-05-13 11:57:09 +03001739 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741
Eliad Peller4a859df2011-06-06 12:21:52 +03001742 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001743 wl12xx_for_each_wlvif(wl, wlvif) {
1744 ret = wl1271_configure_suspend(wl, wlvif);
1745 if (ret < 0) {
1746 wl1271_warning("couldn't prepare device to suspend");
1747 return ret;
1748 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001749 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001750 /* flush any remaining work */
1751 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001752
1753 /*
1754 * disable and re-enable interrupts in order to flush
1755 * the threaded_irq
1756 */
1757 wl1271_disable_interrupts(wl);
1758
1759 /*
1760 * set suspended flag to avoid triggering a new threaded_irq
1761 * work. no need for spinlock as interrupts are disabled.
1762 */
1763 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1764
1765 wl1271_enable_interrupts(wl);
1766 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001767 wl12xx_for_each_wlvif(wl, wlvif) {
1768 flush_delayed_work(&wlvif->pspoll_work);
1769 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001770 flush_delayed_work(&wl->elp_work);
1771
Eliad Peller402e48612011-05-13 11:57:09 +03001772 return 0;
1773}
1774
1775static int wl1271_op_resume(struct ieee80211_hw *hw)
1776{
1777 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001778 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001779 unsigned long flags;
1780 bool run_irq_work = false;
1781
Eliad Peller402e48612011-05-13 11:57:09 +03001782 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1783 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001784 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001785
1786 /*
1787 * re-enable irq_work enqueuing, and call irq_work directly if
1788 * there is a pending work.
1789 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001790 spin_lock_irqsave(&wl->wl_lock, flags);
1791 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1792 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1793 run_irq_work = true;
1794 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001795
Eliad Peller4a859df2011-06-06 12:21:52 +03001796 if (run_irq_work) {
1797 wl1271_debug(DEBUG_MAC80211,
1798 "run postponed irq_work directly");
1799 wl1271_irq(0, wl);
1800 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001801 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001802 wl12xx_for_each_wlvif(wl, wlvif) {
1803 wl1271_configure_resume(wl, wlvif);
1804 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001805 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001806
Eliad Peller402e48612011-05-13 11:57:09 +03001807 return 0;
1808}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001809#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001810
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811static int wl1271_op_start(struct ieee80211_hw *hw)
1812{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001813 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1814
1815 /*
1816 * We have to delay the booting of the hardware because
1817 * we need to know the local MAC address before downloading and
1818 * initializing the firmware. The MAC address cannot be changed
1819 * after boot, and without the proper MAC address, the firmware
1820 * will not function properly.
1821 *
1822 * The MAC address is first known when the corresponding interface
1823 * is added. That is where we will initialize the hardware.
1824 */
1825
1826 return 0;
1827}
1828
1829static void wl1271_op_stop(struct ieee80211_hw *hw)
1830{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001831 struct wl1271 *wl = hw->priv;
1832 int i;
1833
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001834 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001835
Eliad Peller10c8cd02011-10-10 10:13:06 +02001836 mutex_lock(&wl->mutex);
1837 if (wl->state == WL1271_STATE_OFF) {
1838 mutex_unlock(&wl->mutex);
1839 return;
1840 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001841 /*
1842 * this must be before the cancel_work calls below, so that the work
1843 * functions don't perform further work.
1844 */
1845 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001846 mutex_unlock(&wl->mutex);
1847
1848 mutex_lock(&wl_list_mutex);
1849 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001850 mutex_unlock(&wl_list_mutex);
1851
1852 wl1271_disable_interrupts(wl);
1853 wl1271_flush_deferred_work(wl);
1854 cancel_delayed_work_sync(&wl->scan_complete_work);
1855 cancel_work_sync(&wl->netstack_work);
1856 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001857 cancel_delayed_work_sync(&wl->elp_work);
1858
1859 /* let's notify MAC80211 about the remaining pending TX frames */
1860 wl12xx_tx_reset(wl, true);
1861 mutex_lock(&wl->mutex);
1862
1863 wl1271_power_off(wl);
1864
1865 wl->band = IEEE80211_BAND_2GHZ;
1866
1867 wl->rx_counter = 0;
1868 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1869 wl->tx_blocks_available = 0;
1870 wl->tx_allocated_blocks = 0;
1871 wl->tx_results_count = 0;
1872 wl->tx_packets_count = 0;
1873 wl->time_offset = 0;
1874 wl->vif = NULL;
1875 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1876 wl->ap_fw_ps_map = 0;
1877 wl->ap_ps_map = 0;
1878 wl->sched_scanning = false;
1879 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1880 memset(wl->links_map, 0, sizeof(wl->links_map));
1881 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1882 wl->active_sta_count = 0;
1883
1884 /* The system link is always allocated */
1885 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1886
1887 /*
1888 * this is performed after the cancel_work calls and the associated
1889 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1890 * get executed before all these vars have been reset.
1891 */
1892 wl->flags = 0;
1893
1894 wl->tx_blocks_freed = 0;
1895
1896 for (i = 0; i < NUM_TX_QUEUES; i++) {
1897 wl->tx_pkts_freed[i] = 0;
1898 wl->tx_allocated_pkts[i] = 0;
1899 }
1900
1901 wl1271_debugfs_reset(wl);
1902
1903 kfree(wl->fw_status);
1904 wl->fw_status = NULL;
1905 kfree(wl->tx_res_if);
1906 wl->tx_res_if = NULL;
1907 kfree(wl->target_mem_map);
1908 wl->target_mem_map = NULL;
1909
1910 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001911}
1912
Eliad Pellere5a359f2011-10-10 10:13:15 +02001913static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1914{
1915 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1916 WL12XX_MAX_RATE_POLICIES);
1917 if (policy >= WL12XX_MAX_RATE_POLICIES)
1918 return -EBUSY;
1919
1920 __set_bit(policy, wl->rate_policies_map);
1921 *idx = policy;
1922 return 0;
1923}
1924
1925static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1926{
1927 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1928 return;
1929
1930 __clear_bit(*idx, wl->rate_policies_map);
1931 *idx = WL12XX_MAX_RATE_POLICIES;
1932}
1933
Eliad Peller536129c2011-10-05 11:55:45 +02001934static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001935{
Eliad Peller536129c2011-10-05 11:55:45 +02001936 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001937 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001938 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001939 return WL1271_ROLE_P2P_GO;
1940 else
1941 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001942
1943 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001944 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001945 return WL1271_ROLE_P2P_CL;
1946 else
1947 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001948
Eliad Peller227e81e2011-08-14 13:17:26 +03001949 case BSS_TYPE_IBSS:
1950 return WL1271_ROLE_IBSS;
1951
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001952 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001953 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001954 }
1955 return WL12XX_INVALID_ROLE_TYPE;
1956}
1957
Eliad Peller83587502011-10-10 10:12:53 +02001958static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001959{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001960 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001961 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001962
Eliad Peller48e93e42011-10-10 10:12:58 +02001963 /* clear everything but the persistent data */
1964 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001965
1966 switch (ieee80211_vif_type_p2p(vif)) {
1967 case NL80211_IFTYPE_P2P_CLIENT:
1968 wlvif->p2p = 1;
1969 /* fall-through */
1970 case NL80211_IFTYPE_STATION:
1971 wlvif->bss_type = BSS_TYPE_STA_BSS;
1972 break;
1973 case NL80211_IFTYPE_ADHOC:
1974 wlvif->bss_type = BSS_TYPE_IBSS;
1975 break;
1976 case NL80211_IFTYPE_P2P_GO:
1977 wlvif->p2p = 1;
1978 /* fall-through */
1979 case NL80211_IFTYPE_AP:
1980 wlvif->bss_type = BSS_TYPE_AP_BSS;
1981 break;
1982 default:
1983 wlvif->bss_type = MAX_BSS_TYPE;
1984 return -EOPNOTSUPP;
1985 }
1986
Eliad Peller0603d892011-10-05 11:55:51 +02001987 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001988 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001989 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001990
Eliad Pellere936bbe2011-10-05 11:55:56 +02001991 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1992 wlvif->bss_type == BSS_TYPE_IBSS) {
1993 /* init sta/ibss data */
1994 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001995 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1996 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1997 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001998 } else {
1999 /* init ap data */
2000 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2001 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002002 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2003 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2004 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2005 wl12xx_allocate_rate_policy(wl,
2006 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002007 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002008
Eliad Peller83587502011-10-10 10:12:53 +02002009 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2010 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002011 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002012 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002013 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002014 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2015
Eliad Peller1b92f152011-10-10 10:13:09 +02002016 /*
2017 * mac80211 configures some values globally, while we treat them
2018 * per-interface. thus, on init, we have to copy them from wl
2019 */
2020 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002021 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002022 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002023
Eliad Peller9eb599e2011-10-10 10:12:59 +02002024 INIT_WORK(&wlvif->rx_streaming_enable_work,
2025 wl1271_rx_streaming_enable_work);
2026 INIT_WORK(&wlvif->rx_streaming_disable_work,
2027 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002028 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002029 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002030
Eliad Peller9eb599e2011-10-10 10:12:59 +02002031 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2032 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002033 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002034}
2035
Eliad Peller1d095472011-10-10 10:12:49 +02002036static bool wl12xx_init_fw(struct wl1271 *wl)
2037{
2038 int retries = WL1271_BOOT_RETRIES;
2039 bool booted = false;
2040 struct wiphy *wiphy = wl->hw->wiphy;
2041 int ret;
2042
2043 while (retries) {
2044 retries--;
2045 ret = wl1271_chip_wakeup(wl);
2046 if (ret < 0)
2047 goto power_off;
2048
2049 ret = wl1271_boot(wl);
2050 if (ret < 0)
2051 goto power_off;
2052
2053 ret = wl1271_hw_init(wl);
2054 if (ret < 0)
2055 goto irq_disable;
2056
2057 booted = true;
2058 break;
2059
2060irq_disable:
2061 mutex_unlock(&wl->mutex);
2062 /* Unlocking the mutex in the middle of handling is
2063 inherently unsafe. In this case we deem it safe to do,
2064 because we need to let any possibly pending IRQ out of
2065 the system (and while we are WL1271_STATE_OFF the IRQ
2066 work function will not do anything.) Also, any other
2067 possible concurrent operations will fail due to the
2068 current state, hence the wl1271 struct should be safe. */
2069 wl1271_disable_interrupts(wl);
2070 wl1271_flush_deferred_work(wl);
2071 cancel_work_sync(&wl->netstack_work);
2072 mutex_lock(&wl->mutex);
2073power_off:
2074 wl1271_power_off(wl);
2075 }
2076
2077 if (!booted) {
2078 wl1271_error("firmware boot failed despite %d retries",
2079 WL1271_BOOT_RETRIES);
2080 goto out;
2081 }
2082
2083 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2084
2085 /* update hw/fw version info in wiphy struct */
2086 wiphy->hw_version = wl->chip.id;
2087 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2088 sizeof(wiphy->fw_version));
2089
2090 /*
2091 * Now we know if 11a is supported (info from the NVS), so disable
2092 * 11a channels if not supported
2093 */
2094 if (!wl->enable_11a)
2095 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2096
2097 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2098 wl->enable_11a ? "" : "not ");
2099
2100 wl->state = WL1271_STATE_ON;
2101out:
2102 return booted;
2103}
2104
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002105static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2106 struct ieee80211_vif *vif)
2107{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002109 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002111 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002112 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002114 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002115 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002116
2117 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002118 ret = wl1271_ps_elp_wakeup(wl);
2119 if (ret < 0)
2120 goto out_unlock;
2121
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002122 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002123 wl1271_debug(DEBUG_MAC80211,
2124 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002125 ret = -EBUSY;
2126 goto out;
2127 }
2128
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002129 /*
2130 * in some very corner case HW recovery scenarios its possible to
2131 * get here before __wl1271_op_remove_interface is complete, so
2132 * opt out if that is the case.
2133 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002134 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2135 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002136 ret = -EBUSY;
2137 goto out;
2138 }
2139
Eliad Peller83587502011-10-10 10:12:53 +02002140 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002141 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002142 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002143
Eliad Peller252efa42011-10-05 11:56:00 +02002144 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002145 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002146 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2147 ret = -EINVAL;
2148 goto out;
2149 }
Eliad Peller1d095472011-10-10 10:12:49 +02002150
Eliad Peller784f6942011-10-05 11:55:39 +02002151 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002152 * TODO: after the nvs issue will be solved, move this block
2153 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002154 */
Eliad Peller1d095472011-10-10 10:12:49 +02002155 if (wl->state == WL1271_STATE_OFF) {
2156 /*
2157 * we still need this in order to configure the fw
2158 * while uploading the nvs
2159 */
2160 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161
Eliad Peller1d095472011-10-10 10:12:49 +02002162 booted = wl12xx_init_fw(wl);
2163 if (!booted) {
2164 ret = -EINVAL;
2165 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002166 }
Eliad Peller1d095472011-10-10 10:12:49 +02002167 }
Eliad Peller04e80792011-08-14 13:17:09 +03002168
Eliad Peller1d095472011-10-10 10:12:49 +02002169 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2170 wlvif->bss_type == BSS_TYPE_IBSS) {
2171 /*
2172 * The device role is a special role used for
2173 * rx and tx frames prior to association (as
2174 * the STA role can get packets only from
2175 * its associated bssid)
2176 */
Eliad Peller784f6942011-10-05 11:55:39 +02002177 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002178 WL1271_ROLE_DEVICE,
2179 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002180 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002181 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002182 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183
Eliad Peller1d095472011-10-10 10:12:49 +02002184 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2185 role_type, &wlvif->role_id);
2186 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002187 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002188
2189 ret = wl1271_init_vif_specific(wl, vif);
2190 if (ret < 0)
2191 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002192
2193 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002194 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002195 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002196
2197 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2198 wl->ap_count++;
2199 else
2200 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002201out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002202 wl1271_ps_elp_sleep(wl);
2203out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204 mutex_unlock(&wl->mutex);
2205
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002206 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002207 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002208 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002209 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002210
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002211 return ret;
2212}
2213
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002214static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002215 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002216 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217{
Eliad Peller536129c2011-10-05 11:55:45 +02002218 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002219 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002221 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002222
Eliad Peller10c8cd02011-10-10 10:13:06 +02002223 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2224 return;
2225
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002226 /* because of hardware recovery, we may get here twice */
2227 if (wl->state != WL1271_STATE_ON)
2228 return;
2229
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002230 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002232 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002233 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002234 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002235
Eliad Pellerbaf62772011-10-10 10:12:52 +02002236 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2237 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002238 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002239 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002240 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002241 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002242 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002243 }
2244
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002245 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2246 /* disable active roles */
2247 ret = wl1271_ps_elp_wakeup(wl);
2248 if (ret < 0)
2249 goto deinit;
2250
Eliad Peller536129c2011-10-05 11:55:45 +02002251 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002252 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002253 if (ret < 0)
2254 goto deinit;
2255 }
2256
Eliad Peller0603d892011-10-05 11:55:51 +02002257 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002258 if (ret < 0)
2259 goto deinit;
2260
2261 wl1271_ps_elp_sleep(wl);
2262 }
2263deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002264 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002265 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002266
2267 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2268 wlvif->bss_type == BSS_TYPE_IBSS) {
2269 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2270 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2271 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2272 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2273 } else {
2274 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2275 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2276 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2277 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2278 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2279 wl12xx_free_rate_policy(wl,
2280 &wlvif->ap.ucast_rate_idx[i]);
2281 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002282
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002283 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002284 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002285 if (wl->last_wlvif == wlvif)
2286 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002287 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002288 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002289 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002290 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002291
Eliad Pellera4e41302011-10-11 11:49:15 +02002292 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2293 wl->ap_count--;
2294 else
2295 wl->sta_count--;
2296
Eliad Pellerbaf62772011-10-10 10:12:52 +02002297 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002298 del_timer_sync(&wlvif->rx_streaming_timer);
2299 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2300 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002301 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002302
Eliad Pellerbaf62772011-10-10 10:12:52 +02002303 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002304}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002305
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002306static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2307 struct ieee80211_vif *vif)
2308{
2309 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002310 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002312
2313 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002314
2315 if (wl->state == WL1271_STATE_OFF ||
2316 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2317 goto out;
2318
Juuso Oikarinen67353292010-11-18 15:19:02 +02002319 /*
2320 * wl->vif can be null here if someone shuts down the interface
2321 * just when hardware recovery has been started.
2322 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002323 wl12xx_for_each_wlvif(wl, iter) {
2324 if (iter != wlvif)
2325 continue;
2326
Eliad Peller536129c2011-10-05 11:55:45 +02002327 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002328 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002329 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002330 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002331out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002332 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002333 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334}
2335
Eliad Peller87fbcb02011-10-05 11:55:41 +02002336static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2337 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338{
2339 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002340 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002341
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002342 /*
2343 * One of the side effects of the JOIN command is that is clears
2344 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2345 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002346 * Currently the only valid scenario for JOIN during association
2347 * is on roaming, in which case we will also be given new keys.
2348 * Keep the below message for now, unless it starts bothering
2349 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002350 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002351 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002352 wl1271_info("JOIN while associated.");
2353
2354 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002355 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002356
Eliad Peller227e81e2011-08-14 13:17:26 +03002357 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002358 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002359 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002360 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002361 if (ret < 0)
2362 goto out;
2363
Eliad Pellerba8447f2011-10-10 10:13:00 +02002364 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002365 goto out;
2366
2367 /*
2368 * The join command disable the keep-alive mode, shut down its process,
2369 * and also clear the template config, so we need to reset it all after
2370 * the join. The acx_aid starts the keep-alive process, and the order
2371 * of the commands below is relevant.
2372 */
Eliad Peller0603d892011-10-05 11:55:51 +02002373 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002374 if (ret < 0)
2375 goto out;
2376
Eliad Peller0603d892011-10-05 11:55:51 +02002377 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002378 if (ret < 0)
2379 goto out;
2380
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002381 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002382 if (ret < 0)
2383 goto out;
2384
Eliad Peller0603d892011-10-05 11:55:51 +02002385 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2386 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002387 ACX_KEEP_ALIVE_TPL_VALID);
2388 if (ret < 0)
2389 goto out;
2390
2391out:
2392 return ret;
2393}
2394
Eliad Peller0603d892011-10-05 11:55:51 +02002395static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002396{
2397 int ret;
2398
Eliad Peller52630c52011-10-10 10:13:08 +02002399 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002400 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2401
Shahar Levi6d158ff2011-09-08 13:01:33 +03002402 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002403 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002404 }
2405
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002406 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002407 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002408 if (ret < 0)
2409 goto out;
2410
Oz Krakowskib992c682011-06-26 10:36:02 +03002411 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002412 wlvif->tx_security_last_seq_lsb = 0;
2413 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002414
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002415out:
2416 return ret;
2417}
2418
Eliad Peller87fbcb02011-10-05 11:55:41 +02002419static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002420{
Eliad Peller1b92f152011-10-10 10:13:09 +02002421 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002422 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002423}
2424
Eliad Peller251c1772011-08-14 13:17:17 +03002425static bool wl12xx_is_roc(struct wl1271 *wl)
2426{
2427 u8 role_id;
2428
2429 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2430 if (role_id >= WL12XX_MAX_ROLES)
2431 return false;
2432
2433 return true;
2434}
2435
Eliad Peller87fbcb02011-10-05 11:55:41 +02002436static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2437 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438{
2439 int ret;
2440
2441 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002442 /* no need to croc if we weren't busy (e.g. during boot) */
2443 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002444 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002445 if (ret < 0)
2446 goto out;
2447
Eliad Peller7edebf52011-10-05 11:55:52 +02002448 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002449 if (ret < 0)
2450 goto out;
2451 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002452 wlvif->rate_set =
2453 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2454 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 if (ret < 0)
2456 goto out;
2457 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002458 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002459 ACX_KEEP_ALIVE_TPL_INVALID);
2460 if (ret < 0)
2461 goto out;
2462 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2463 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002464 /* The current firmware only supports sched_scan in idle */
2465 if (wl->sched_scanning) {
2466 wl1271_scan_sched_scan_stop(wl);
2467 ieee80211_sched_scan_stopped(wl->hw);
2468 }
2469
Eliad Peller7edebf52011-10-05 11:55:52 +02002470 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002471 if (ret < 0)
2472 goto out;
2473
Eliad Peller1b92f152011-10-10 10:13:09 +02002474 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002475 if (ret < 0)
2476 goto out;
2477 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2478 }
2479
2480out:
2481 return ret;
2482}
2483
Eliad Peller9f259c42011-10-10 10:13:12 +02002484static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2485 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002486{
Eliad Peller9f259c42011-10-10 10:13:12 +02002487 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2488 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002489
2490 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2491
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002492 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002493 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002494 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002495 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002496 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002497 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002498 wlvif->band = conf->channel->band;
2499 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002500
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002501 if (!is_ap) {
2502 /*
2503 * FIXME: the mac80211 should really provide a fixed
2504 * rate to use here. for now, just use the smallest
2505 * possible rate for the band as a fixed rate for
2506 * association frames and other control messages.
2507 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002508 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002509 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002510
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002511 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002512 wl1271_tx_min_rate_get(wl,
2513 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002514 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002515 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002516 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002517 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002518
Eliad Pellerba8447f2011-10-10 10:13:00 +02002519 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2520 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002521 if (wl12xx_is_roc(wl)) {
2522 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002523 ret = wl12xx_croc(wl,
2524 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002525 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002526 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002527 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002528 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002529 if (ret < 0)
2530 wl1271_warning("cmd join on channel "
2531 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002532 } else {
2533 /*
2534 * change the ROC channel. do it only if we are
2535 * not idle. otherwise, CROC will be called
2536 * anyway.
2537 */
2538 if (wl12xx_is_roc(wl) &&
2539 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002540 ret = wl12xx_croc(wl,
2541 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002542 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002543 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002544
Eliad Peller1b92f152011-10-10 10:13:09 +02002545 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002546 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002547 if (ret < 0)
2548 wl1271_warning("roc failed %d",
2549 ret);
2550 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002551 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002552 }
2553 }
2554
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002555 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002556 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002557 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002558 if (ret < 0)
2559 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560 }
2561
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002562 /*
2563 * if mac80211 changes the PSM mode, make sure the mode is not
2564 * incorrectly changed after the pspoll failure active window.
2565 */
2566 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002567 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002568
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002569 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002570 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2571 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572
2573 /*
2574 * We enter PSM only if we're already associated.
2575 * If we're not, we'll enter it when joining an SSID,
2576 * through the bss_info_changed() hook.
2577 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002578 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002579 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002580 ret = wl1271_ps_set_mode(wl, wlvif,
2581 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002582 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002583 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002585 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002586 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587
Eliad Pellerc29bb002011-10-10 10:13:03 +02002588 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589
Eliad Pellerc29bb002011-10-10 10:13:03 +02002590 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002591 ret = wl1271_ps_set_mode(wl, wlvif,
2592 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002593 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594 }
2595
Eliad Peller6bd65022011-10-10 10:13:11 +02002596 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002597 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002598 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002599 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002600
Eliad Peller6bd65022011-10-10 10:13:11 +02002601 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602 }
2603
Eliad Peller9f259c42011-10-10 10:13:12 +02002604 return 0;
2605}
2606
2607static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2608{
2609 struct wl1271 *wl = hw->priv;
2610 struct wl12xx_vif *wlvif;
2611 struct ieee80211_conf *conf = &hw->conf;
2612 int channel, ret = 0;
2613
2614 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2615
2616 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2617 " changed 0x%x",
2618 channel,
2619 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2620 conf->power_level,
2621 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2622 changed);
2623
2624 /*
2625 * mac80211 will go to idle nearly immediately after transmitting some
2626 * frames, such as the deauth. To make sure those frames reach the air,
2627 * wait here until the TX queue is fully flushed.
2628 */
2629 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2630 (conf->flags & IEEE80211_CONF_IDLE))
2631 wl1271_tx_flush(wl);
2632
2633 mutex_lock(&wl->mutex);
2634
2635 /* we support configuring the channel and band even while off */
2636 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2637 wl->band = conf->channel->band;
2638 wl->channel = channel;
2639 }
2640
2641 if (changed & IEEE80211_CONF_CHANGE_POWER)
2642 wl->power_level = conf->power_level;
2643
2644 if (unlikely(wl->state == WL1271_STATE_OFF))
2645 goto out;
2646
2647 ret = wl1271_ps_elp_wakeup(wl);
2648 if (ret < 0)
2649 goto out;
2650
2651 /* configure each interface */
2652 wl12xx_for_each_wlvif(wl, wlvif) {
2653 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2654 if (ret < 0)
2655 goto out_sleep;
2656 }
2657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658out_sleep:
2659 wl1271_ps_elp_sleep(wl);
2660
2661out:
2662 mutex_unlock(&wl->mutex);
2663
2664 return ret;
2665}
2666
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002667struct wl1271_filter_params {
2668 bool enabled;
2669 int mc_list_length;
2670 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2671};
2672
Jiri Pirko22bedad2010-04-01 21:22:57 +00002673static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2674 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002675{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002676 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002677 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002678 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002679
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002680 if (unlikely(wl->state == WL1271_STATE_OFF))
2681 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002682
Juuso Oikarinen74441132009-10-13 12:47:53 +03002683 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002684 if (!fp) {
2685 wl1271_error("Out of memory setting filters.");
2686 return 0;
2687 }
2688
2689 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002690 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002691 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2692 fp->enabled = false;
2693 } else {
2694 fp->enabled = true;
2695 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002696 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002697 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002698 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002699 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002700 }
2701
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002702 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002703}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002705#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2706 FIF_ALLMULTI | \
2707 FIF_FCSFAIL | \
2708 FIF_BCN_PRBRESP_PROMISC | \
2709 FIF_CONTROL | \
2710 FIF_OTHER_BSS)
2711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2713 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002714 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002715{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002716 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002718 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002719
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002720 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721
Arik Nemtsov7d057862010-10-16 19:25:35 +02002722 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2723 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002725 mutex_lock(&wl->mutex);
2726
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002727 *total &= WL1271_SUPPORTED_FILTERS;
2728 changed &= WL1271_SUPPORTED_FILTERS;
2729
2730 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002731 goto out;
2732
Ido Yariva6208652011-03-01 15:14:41 +02002733 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002734 if (ret < 0)
2735 goto out;
2736
Eliad Peller6e8cd332011-10-10 10:13:13 +02002737 wl12xx_for_each_wlvif(wl, wlvif) {
2738 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2739 if (*total & FIF_ALLMULTI)
2740 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2741 false,
2742 NULL, 0);
2743 else if (fp)
2744 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2745 fp->enabled,
2746 fp->mc_list,
2747 fp->mc_list_length);
2748 if (ret < 0)
2749 goto out_sleep;
2750 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002751 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002753 /*
2754 * the fw doesn't provide an api to configure the filters. instead,
2755 * the filters configuration is based on the active roles / ROC
2756 * state.
2757 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002758
2759out_sleep:
2760 wl1271_ps_elp_sleep(wl);
2761
2762out:
2763 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002764 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002765}
2766
Eliad Peller170d0e62011-10-05 11:56:06 +02002767static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2768 u8 id, u8 key_type, u8 key_size,
2769 const u8 *key, u8 hlid, u32 tx_seq_32,
2770 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771{
2772 struct wl1271_ap_key *ap_key;
2773 int i;
2774
2775 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2776
2777 if (key_size > MAX_KEY_SIZE)
2778 return -EINVAL;
2779
2780 /*
2781 * Find next free entry in ap_keys. Also check we are not replacing
2782 * an existing key.
2783 */
2784 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002785 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002786 break;
2787
Eliad Peller170d0e62011-10-05 11:56:06 +02002788 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002789 wl1271_warning("trying to record key replacement");
2790 return -EINVAL;
2791 }
2792 }
2793
2794 if (i == MAX_NUM_KEYS)
2795 return -EBUSY;
2796
2797 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2798 if (!ap_key)
2799 return -ENOMEM;
2800
2801 ap_key->id = id;
2802 ap_key->key_type = key_type;
2803 ap_key->key_size = key_size;
2804 memcpy(ap_key->key, key, key_size);
2805 ap_key->hlid = hlid;
2806 ap_key->tx_seq_32 = tx_seq_32;
2807 ap_key->tx_seq_16 = tx_seq_16;
2808
Eliad Peller170d0e62011-10-05 11:56:06 +02002809 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002810 return 0;
2811}
2812
Eliad Peller170d0e62011-10-05 11:56:06 +02002813static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814{
2815 int i;
2816
2817 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002818 kfree(wlvif->ap.recorded_keys[i]);
2819 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002820 }
2821}
2822
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002823static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824{
2825 int i, ret = 0;
2826 struct wl1271_ap_key *key;
2827 bool wep_key_added = false;
2828
2829 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002830 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002831 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002832 break;
2833
Eliad Peller170d0e62011-10-05 11:56:06 +02002834 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002835 hlid = key->hlid;
2836 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002837 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002838
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002839 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002840 key->id, key->key_type,
2841 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002842 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002843 key->tx_seq_16);
2844 if (ret < 0)
2845 goto out;
2846
2847 if (key->key_type == KEY_WEP)
2848 wep_key_added = true;
2849 }
2850
2851 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002852 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002853 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002854 if (ret < 0)
2855 goto out;
2856 }
2857
2858out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002859 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002860 return ret;
2861}
2862
Eliad Peller536129c2011-10-05 11:55:45 +02002863static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2864 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 u8 key_size, const u8 *key, u32 tx_seq_32,
2866 u16 tx_seq_16, struct ieee80211_sta *sta)
2867{
2868 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002869 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002870
2871 if (is_ap) {
2872 struct wl1271_station *wl_sta;
2873 u8 hlid;
2874
2875 if (sta) {
2876 wl_sta = (struct wl1271_station *)sta->drv_priv;
2877 hlid = wl_sta->hlid;
2878 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002879 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002880 }
2881
Eliad Peller53d40d02011-10-10 10:13:02 +02002882 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002883 /*
2884 * We do not support removing keys after AP shutdown.
2885 * Pretend we do to make mac80211 happy.
2886 */
2887 if (action != KEY_ADD_OR_REPLACE)
2888 return 0;
2889
Eliad Peller170d0e62011-10-05 11:56:06 +02002890 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002891 key_type, key_size,
2892 key, hlid, tx_seq_32,
2893 tx_seq_16);
2894 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002895 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002896 id, key_type, key_size,
2897 key, hlid, tx_seq_32,
2898 tx_seq_16);
2899 }
2900
2901 if (ret < 0)
2902 return ret;
2903 } else {
2904 const u8 *addr;
2905 static const u8 bcast_addr[ETH_ALEN] = {
2906 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2907 };
2908
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002909 /*
2910 * A STA set to GEM cipher requires 2 tx spare blocks.
2911 * Return to default value when GEM cipher key is removed
2912 */
2913 if (key_type == KEY_GEM) {
2914 if (action == KEY_ADD_OR_REPLACE)
2915 wl->tx_spare_blocks = 2;
2916 else if (action == KEY_REMOVE)
2917 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2918 }
2919
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002920 addr = sta ? sta->addr : bcast_addr;
2921
2922 if (is_zero_ether_addr(addr)) {
2923 /* We dont support TX only encryption */
2924 return -EOPNOTSUPP;
2925 }
2926
2927 /* The wl1271 does not allow to remove unicast keys - they
2928 will be cleared automatically on next CMD_JOIN. Ignore the
2929 request silently, as we dont want the mac80211 to emit
2930 an error message. */
2931 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2932 return 0;
2933
Eliad Peller010d3d32011-08-14 13:17:31 +03002934 /* don't remove key if hlid was already deleted */
2935 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002936 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002937 return 0;
2938
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002939 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002940 id, key_type, key_size,
2941 key, addr, tx_seq_32,
2942 tx_seq_16);
2943 if (ret < 0)
2944 return ret;
2945
2946 /* the default WEP key needs to be configured at least once */
2947 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002948 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002949 wlvif->default_key,
2950 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002951 if (ret < 0)
2952 return ret;
2953 }
2954 }
2955
2956 return 0;
2957}
2958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2960 struct ieee80211_vif *vif,
2961 struct ieee80211_sta *sta,
2962 struct ieee80211_key_conf *key_conf)
2963{
2964 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002965 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002967 u32 tx_seq_32 = 0;
2968 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969 u8 key_type;
2970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2972
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002973 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002974 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002975 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002976 key_conf->keylen, key_conf->flags);
2977 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979 mutex_lock(&wl->mutex);
2980
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002981 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2982 ret = -EAGAIN;
2983 goto out_unlock;
2984 }
2985
Ido Yariva6208652011-03-01 15:14:41 +02002986 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 if (ret < 0)
2988 goto out_unlock;
2989
Johannes Berg97359d12010-08-10 09:46:38 +02002990 switch (key_conf->cipher) {
2991 case WLAN_CIPHER_SUITE_WEP40:
2992 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 key_type = KEY_WEP;
2994
2995 key_conf->hw_key_idx = key_conf->keyidx;
2996 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002997 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002998 key_type = KEY_TKIP;
2999
3000 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02003001 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3002 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003004 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005 key_type = KEY_AES;
3006
3007 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02003008 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3009 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003011 case WL1271_CIPHER_SUITE_GEM:
3012 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02003013 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3014 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003015 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003017 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018
3019 ret = -EOPNOTSUPP;
3020 goto out_sleep;
3021 }
3022
3023 switch (cmd) {
3024 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003025 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003026 key_conf->keyidx, key_type,
3027 key_conf->keylen, key_conf->key,
3028 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029 if (ret < 0) {
3030 wl1271_error("Could not add or replace key");
3031 goto out_sleep;
3032 }
3033 break;
3034
3035 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003036 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003037 key_conf->keyidx, key_type,
3038 key_conf->keylen, key_conf->key,
3039 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040 if (ret < 0) {
3041 wl1271_error("Could not remove key");
3042 goto out_sleep;
3043 }
3044 break;
3045
3046 default:
3047 wl1271_error("Unsupported key cmd 0x%x", cmd);
3048 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049 break;
3050 }
3051
3052out_sleep:
3053 wl1271_ps_elp_sleep(wl);
3054
3055out_unlock:
3056 mutex_unlock(&wl->mutex);
3057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003058 return ret;
3059}
3060
3061static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003062 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003063 struct cfg80211_scan_request *req)
3064{
3065 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003066 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3067
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003068 int ret;
3069 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003070 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003071
3072 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3073
3074 if (req->n_ssids) {
3075 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003076 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077 }
3078
3079 mutex_lock(&wl->mutex);
3080
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003081 if (wl->state == WL1271_STATE_OFF) {
3082 /*
3083 * We cannot return -EBUSY here because cfg80211 will expect
3084 * a call to ieee80211_scan_completed if we do - in this case
3085 * there won't be any call.
3086 */
3087 ret = -EAGAIN;
3088 goto out;
3089 }
3090
Ido Yariva6208652011-03-01 15:14:41 +02003091 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003092 if (ret < 0)
3093 goto out;
3094
Eliad Peller251c1772011-08-14 13:17:17 +03003095 /* cancel ROC before scanning */
3096 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003097 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003098 /* don't allow scanning right now */
3099 ret = -EBUSY;
3100 goto out_sleep;
3101 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003102 wl12xx_croc(wl, wlvif->dev_role_id);
3103 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003104 }
3105
Eliad Peller784f6942011-10-05 11:55:39 +02003106 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003107out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003108 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109out:
3110 mutex_unlock(&wl->mutex);
3111
3112 return ret;
3113}
3114
Eliad Peller73ecce32011-06-27 13:06:45 +03003115static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3116 struct ieee80211_vif *vif)
3117{
3118 struct wl1271 *wl = hw->priv;
3119 int ret;
3120
3121 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3122
3123 mutex_lock(&wl->mutex);
3124
3125 if (wl->state == WL1271_STATE_OFF)
3126 goto out;
3127
3128 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3129 goto out;
3130
3131 ret = wl1271_ps_elp_wakeup(wl);
3132 if (ret < 0)
3133 goto out;
3134
3135 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3136 ret = wl1271_scan_stop(wl);
3137 if (ret < 0)
3138 goto out_sleep;
3139 }
3140 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3141 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003142 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003143 wl->scan.req = NULL;
3144 ieee80211_scan_completed(wl->hw, true);
3145
3146out_sleep:
3147 wl1271_ps_elp_sleep(wl);
3148out:
3149 mutex_unlock(&wl->mutex);
3150
3151 cancel_delayed_work_sync(&wl->scan_complete_work);
3152}
3153
Luciano Coelho33c2c062011-05-10 14:46:02 +03003154static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3155 struct ieee80211_vif *vif,
3156 struct cfg80211_sched_scan_request *req,
3157 struct ieee80211_sched_scan_ies *ies)
3158{
3159 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003160 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003161 int ret;
3162
3163 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3164
3165 mutex_lock(&wl->mutex);
3166
3167 ret = wl1271_ps_elp_wakeup(wl);
3168 if (ret < 0)
3169 goto out;
3170
Eliad Peller536129c2011-10-05 11:55:45 +02003171 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003172 if (ret < 0)
3173 goto out_sleep;
3174
Eliad Peller536129c2011-10-05 11:55:45 +02003175 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003176 if (ret < 0)
3177 goto out_sleep;
3178
3179 wl->sched_scanning = true;
3180
3181out_sleep:
3182 wl1271_ps_elp_sleep(wl);
3183out:
3184 mutex_unlock(&wl->mutex);
3185 return ret;
3186}
3187
3188static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3189 struct ieee80211_vif *vif)
3190{
3191 struct wl1271 *wl = hw->priv;
3192 int ret;
3193
3194 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3195
3196 mutex_lock(&wl->mutex);
3197
3198 ret = wl1271_ps_elp_wakeup(wl);
3199 if (ret < 0)
3200 goto out;
3201
3202 wl1271_scan_sched_scan_stop(wl);
3203
3204 wl1271_ps_elp_sleep(wl);
3205out:
3206 mutex_unlock(&wl->mutex);
3207}
3208
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003209static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3210{
3211 struct wl1271 *wl = hw->priv;
3212 int ret = 0;
3213
3214 mutex_lock(&wl->mutex);
3215
3216 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3217 ret = -EAGAIN;
3218 goto out;
3219 }
3220
Ido Yariva6208652011-03-01 15:14:41 +02003221 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003222 if (ret < 0)
3223 goto out;
3224
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003225 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003226 if (ret < 0)
3227 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3228
3229 wl1271_ps_elp_sleep(wl);
3230
3231out:
3232 mutex_unlock(&wl->mutex);
3233
3234 return ret;
3235}
3236
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003237static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3238{
3239 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003240 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003241 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003242
3243 mutex_lock(&wl->mutex);
3244
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003245 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3246 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003247 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003248 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003249
Ido Yariva6208652011-03-01 15:14:41 +02003250 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003251 if (ret < 0)
3252 goto out;
3253
Eliad Peller6e8cd332011-10-10 10:13:13 +02003254 wl12xx_for_each_wlvif(wl, wlvif) {
3255 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3256 if (ret < 0)
3257 wl1271_warning("set rts threshold failed: %d", ret);
3258 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003259 wl1271_ps_elp_sleep(wl);
3260
3261out:
3262 mutex_unlock(&wl->mutex);
3263
3264 return ret;
3265}
3266
Eliad Peller1fe9f162011-10-05 11:55:48 +02003267static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003268 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003269{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003270 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003271 u8 ssid_len;
3272 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3273 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003274
Eliad Peller889cb362011-05-01 09:56:45 +03003275 if (!ptr) {
3276 wl1271_error("No SSID in IEs!");
3277 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003278 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003279
Eliad Peller889cb362011-05-01 09:56:45 +03003280 ssid_len = ptr[1];
3281 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3282 wl1271_error("SSID is too long!");
3283 return -EINVAL;
3284 }
3285
Eliad Peller1fe9f162011-10-05 11:55:48 +02003286 wlvif->ssid_len = ssid_len;
3287 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003288 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003289}
3290
Eliad Pellerd48055d2011-09-15 12:07:04 +03003291static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3292{
3293 int len;
3294 const u8 *next, *end = skb->data + skb->len;
3295 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3296 skb->len - ieoffset);
3297 if (!ie)
3298 return;
3299 len = ie[1] + 2;
3300 next = ie + len;
3301 memmove(ie, next, end - next);
3302 skb_trim(skb, skb->len - len);
3303}
3304
Eliad Peller26b4bf22011-09-15 12:07:05 +03003305static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3306 unsigned int oui, u8 oui_type,
3307 int ieoffset)
3308{
3309 int len;
3310 const u8 *next, *end = skb->data + skb->len;
3311 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3312 skb->data + ieoffset,
3313 skb->len - ieoffset);
3314 if (!ie)
3315 return;
3316 len = ie[1] + 2;
3317 next = ie + len;
3318 memmove(ie, next, end - next);
3319 skb_trim(skb, skb->len - len);
3320}
3321
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003322static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003323 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003324 u8 *probe_rsp_data,
3325 size_t probe_rsp_len,
3326 u32 rates)
3327{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003328 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3329 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003330 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3331 int ssid_ie_offset, ie_offset, templ_len;
3332 const u8 *ptr;
3333
3334 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003335 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003336 return wl1271_cmd_template_set(wl,
3337 CMD_TEMPL_AP_PROBE_RESPONSE,
3338 probe_rsp_data,
3339 probe_rsp_len, 0,
3340 rates);
3341
3342 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3343 wl1271_error("probe_rsp template too big");
3344 return -EINVAL;
3345 }
3346
3347 /* start searching from IE offset */
3348 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3349
3350 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3351 probe_rsp_len - ie_offset);
3352 if (!ptr) {
3353 wl1271_error("No SSID in beacon!");
3354 return -EINVAL;
3355 }
3356
3357 ssid_ie_offset = ptr - probe_rsp_data;
3358 ptr += (ptr[1] + 2);
3359
3360 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3361
3362 /* insert SSID from bss_conf */
3363 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3364 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3365 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3366 bss_conf->ssid, bss_conf->ssid_len);
3367 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3368
3369 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3370 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3371 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3372
3373 return wl1271_cmd_template_set(wl,
3374 CMD_TEMPL_AP_PROBE_RESPONSE,
3375 probe_rsp_templ,
3376 templ_len, 0,
3377 rates);
3378}
3379
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003381 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003382 struct ieee80211_bss_conf *bss_conf,
3383 u32 changed)
3384{
Eliad Peller0603d892011-10-05 11:55:51 +02003385 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 int ret = 0;
3387
3388 if (changed & BSS_CHANGED_ERP_SLOT) {
3389 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003390 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 else
Eliad Peller0603d892011-10-05 11:55:51 +02003392 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 if (ret < 0) {
3394 wl1271_warning("Set slot time failed %d", ret);
3395 goto out;
3396 }
3397 }
3398
3399 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3400 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003401 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 else
Eliad Peller0603d892011-10-05 11:55:51 +02003403 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 }
3405
3406 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3407 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003408 ret = wl1271_acx_cts_protect(wl, wlvif,
3409 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 else
Eliad Peller0603d892011-10-05 11:55:51 +02003411 ret = wl1271_acx_cts_protect(wl, wlvif,
3412 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 if (ret < 0) {
3414 wl1271_warning("Set ctsprotect failed %d", ret);
3415 goto out;
3416 }
3417 }
3418
3419out:
3420 return ret;
3421}
3422
3423static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3424 struct ieee80211_vif *vif,
3425 struct ieee80211_bss_conf *bss_conf,
3426 u32 changed)
3427{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003428 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003429 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 int ret = 0;
3431
3432 if ((changed & BSS_CHANGED_BEACON_INT)) {
3433 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3434 bss_conf->beacon_int);
3435
Eliad Peller6a899792011-10-05 11:55:58 +02003436 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 }
3438
3439 if ((changed & BSS_CHANGED_BEACON)) {
3440 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003441 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 int ieoffset = offsetof(struct ieee80211_mgmt,
3443 u.beacon.variable);
3444 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3445 u16 tmpl_id;
3446
3447 if (!beacon)
3448 goto out;
3449
3450 wl1271_debug(DEBUG_MASTER, "beacon updated");
3451
Eliad Peller1fe9f162011-10-05 11:55:48 +02003452 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003453 if (ret < 0) {
3454 dev_kfree_skb(beacon);
3455 goto out;
3456 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003457 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3459 CMD_TEMPL_BEACON;
3460 ret = wl1271_cmd_template_set(wl, tmpl_id,
3461 beacon->data,
3462 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003463 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 if (ret < 0) {
3465 dev_kfree_skb(beacon);
3466 goto out;
3467 }
3468
Eliad Pellerd48055d2011-09-15 12:07:04 +03003469 /* remove TIM ie from probe response */
3470 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3471
Eliad Peller26b4bf22011-09-15 12:07:05 +03003472 /*
3473 * remove p2p ie from probe response.
3474 * the fw reponds to probe requests that don't include
3475 * the p2p ie. probe requests with p2p ie will be passed,
3476 * and will be responded by the supplicant (the spec
3477 * forbids including the p2p ie when responding to probe
3478 * requests that didn't include it).
3479 */
3480 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3481 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3482
Arik Nemtsove78a2872010-10-16 19:07:21 +02003483 hdr = (struct ieee80211_hdr *) beacon->data;
3484 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3485 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003486 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003487 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003488 beacon->data,
3489 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003490 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003491 else
3492 ret = wl1271_cmd_template_set(wl,
3493 CMD_TEMPL_PROBE_RESPONSE,
3494 beacon->data,
3495 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003496 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003497 dev_kfree_skb(beacon);
3498 if (ret < 0)
3499 goto out;
3500 }
3501
3502out:
3503 return ret;
3504}
3505
3506/* AP mode changes */
3507static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003508 struct ieee80211_vif *vif,
3509 struct ieee80211_bss_conf *bss_conf,
3510 u32 changed)
3511{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003512 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3516 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003517
Eliad Peller87fbcb02011-10-05 11:55:41 +02003518 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003519 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003520 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003521 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003522
Eliad Peller87fbcb02011-10-05 11:55:41 +02003523 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003524 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003525 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003527 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003528
Eliad Peller784f6942011-10-05 11:55:39 +02003529 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003530 if (ret < 0)
3531 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003532 }
3533
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3535 if (ret < 0)
3536 goto out;
3537
3538 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3539 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003540 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003541 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0)
3543 goto out;
3544
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003545 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003546 if (ret < 0)
3547 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003548
Eliad Peller53d40d02011-10-10 10:13:02 +02003549 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003550 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003551 }
3552 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003553 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003554 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 if (ret < 0)
3556 goto out;
3557
Eliad Peller53d40d02011-10-10 10:13:02 +02003558 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003559 wl1271_debug(DEBUG_AP, "stopped AP");
3560 }
3561 }
3562 }
3563
Eliad Peller0603d892011-10-05 11:55:51 +02003564 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003565 if (ret < 0)
3566 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003567
3568 /* Handle HT information change */
3569 if ((changed & BSS_CHANGED_HT) &&
3570 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003571 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003572 bss_conf->ht_operation_mode);
3573 if (ret < 0) {
3574 wl1271_warning("Set ht information failed %d", ret);
3575 goto out;
3576 }
3577 }
3578
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579out:
3580 return;
3581}
3582
3583/* STA/IBSS mode changes */
3584static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3585 struct ieee80211_vif *vif,
3586 struct ieee80211_bss_conf *bss_conf,
3587 u32 changed)
3588{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003589 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003590 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003591 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003592 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003593 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003594 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003595 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003596 bool sta_exists = false;
3597 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003598
3599 if (is_ibss) {
3600 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3601 changed);
3602 if (ret < 0)
3603 goto out;
3604 }
3605
Eliad Peller227e81e2011-08-14 13:17:26 +03003606 if (changed & BSS_CHANGED_IBSS) {
3607 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003608 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 ibss_joined = true;
3610 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003611 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3612 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003613 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003614 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003615 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003616 }
3617 }
3618 }
3619
3620 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003621 do_join = true;
3622
3623 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003624 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003625 do_join = true;
3626
Eliad Peller227e81e2011-08-14 13:17:26 +03003627 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003628 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3629 bss_conf->enable_beacon ? "enabled" : "disabled");
3630
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003631 do_join = true;
3632 }
3633
Arik Nemtsove78a2872010-10-16 19:07:21 +02003634 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003635 bool enable = false;
3636 if (bss_conf->cqm_rssi_thold)
3637 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003638 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003639 bss_conf->cqm_rssi_thold,
3640 bss_conf->cqm_rssi_hyst);
3641 if (ret < 0)
3642 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003643 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003644 }
3645
Eliad Pellercdf09492011-10-05 11:55:44 +02003646 if (changed & BSS_CHANGED_BSSID)
3647 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003648 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003649 if (ret < 0)
3650 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003651
Eliad Peller784f6942011-10-05 11:55:39 +02003652 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003653 if (ret < 0)
3654 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003655
Eliad Pellerfa287b82010-12-26 09:27:50 +01003656 /* Need to update the BSSID (for filtering etc) */
3657 do_join = true;
3658 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003659
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003660 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3661 rcu_read_lock();
3662 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3663 if (!sta)
3664 goto sta_not_found;
3665
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003666 /* save the supp_rates of the ap */
3667 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3668 if (sta->ht_cap.ht_supported)
3669 sta_rate_set |=
3670 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003671 sta_ht_cap = sta->ht_cap;
3672 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003673
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003674sta_not_found:
3675 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003676 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003677
Arik Nemtsove78a2872010-10-16 19:07:21 +02003678 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003679 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003680 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003681 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003682 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003683 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003684
Eliad Peller74ec8392011-10-05 11:56:02 +02003685 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003686
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003687 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003688 * use basic rates from AP, and determine lowest rate
3689 * to use with control frames.
3690 */
3691 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003692 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003693 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003694 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003695 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003696 wl1271_tx_min_rate_get(wl,
3697 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003698 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003699 wlvif->rate_set =
3700 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003701 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003702 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003703 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003704 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003705 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003706
3707 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003708 * with wl1271, we don't need to update the
3709 * beacon_int and dtim_period, because the firmware
3710 * updates it by itself when the first beacon is
3711 * received after a join.
3712 */
Eliad Peller6840e372011-10-05 11:55:50 +02003713 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003714 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003715 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003716
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003717 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003718 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003719 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003720 dev_kfree_skb(wlvif->probereq);
3721 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003722 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003723 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003724 ieoffset = offsetof(struct ieee80211_mgmt,
3725 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003726 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003727
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003728 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003729 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003730 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003731 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003732 } else {
3733 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003734 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003735 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3736 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003737 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003738 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3739 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003740 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003741
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003742 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003743 dev_kfree_skb(wlvif->probereq);
3744 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003745
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003746 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003747 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003748
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003749 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003750 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003751 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003752 wl1271_tx_min_rate_get(wl,
3753 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003754 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003755 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003756 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003757
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003758 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003759 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003760
3761 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003762 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003763 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003764 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003765
3766 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003767 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003768 u32 conf_flags = wl->hw->conf.flags;
3769 /*
3770 * we might have to disable roc, if there was
3771 * no IF_OPER_UP notification.
3772 */
3773 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003774 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003775 if (ret < 0)
3776 goto out;
3777 }
3778 /*
3779 * (we also need to disable roc in case of
3780 * roaming on the same channel. until we will
3781 * have a better flow...)
3782 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003783 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3784 ret = wl12xx_croc(wl,
3785 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003786 if (ret < 0)
3787 goto out;
3788 }
3789
Eliad Peller0603d892011-10-05 11:55:51 +02003790 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003791 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003792 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003793 wl12xx_roc(wl, wlvif,
3794 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003795 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003796 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003797 }
3798 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003799
Eliad Pellerd192d262011-05-24 14:33:08 +03003800 if (changed & BSS_CHANGED_IBSS) {
3801 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3802 bss_conf->ibss_joined);
3803
3804 if (bss_conf->ibss_joined) {
3805 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003806 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003807 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003808 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003809 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003810 wl1271_tx_min_rate_get(wl,
3811 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003812
Shahar Levi06b660e2011-09-05 13:54:36 +03003813 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003814 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3815 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003816 if (ret < 0)
3817 goto out;
3818 }
3819 }
3820
Eliad Peller0603d892011-10-05 11:55:51 +02003821 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003822 if (ret < 0)
3823 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003824
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003825 if (changed & BSS_CHANGED_ARP_FILTER) {
3826 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003827 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003828
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 if (bss_conf->arp_addr_cnt == 1 &&
3830 bss_conf->arp_filter_enabled) {
3831 /*
3832 * The template should have been configured only upon
3833 * association. however, it seems that the correct ip
3834 * isn't being set (when sending), so we have to
3835 * reconfigure the template upon every ip change.
3836 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003837 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003838 if (ret < 0) {
3839 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003840 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003841 }
3842
Eliad Peller0603d892011-10-05 11:55:51 +02003843 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003844 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003845 addr);
3846 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003847 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003848
3849 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003850 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003851 }
3852
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003853 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003854 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003855 if (ret < 0) {
3856 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003857 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003858 }
Eliad Peller251c1772011-08-14 13:17:17 +03003859
3860 /* ROC until connected (after EAPOL exchange) */
3861 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003862 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003863 if (ret < 0)
3864 goto out;
3865
Eliad Pellerba8447f2011-10-10 10:13:00 +02003866 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003867 ieee80211_get_operstate(vif));
3868 }
3869 /*
3870 * stop device role if started (we might already be in
3871 * STA role). TODO: make it better.
3872 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003873 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3874 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003875 if (ret < 0)
3876 goto out;
3877
Eliad Peller7edebf52011-10-05 11:55:52 +02003878 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003879 if (ret < 0)
3880 goto out;
3881 }
Eliad Peller05dba352011-08-23 16:37:01 +03003882
3883 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003884 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3885 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003886 enum wl1271_cmd_ps_mode mode;
3887
3888 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003889 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003890 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003891 true);
3892 if (ret < 0)
3893 goto out;
3894 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003895 }
3896
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003897 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003898 if (sta_exists) {
3899 if ((changed & BSS_CHANGED_HT) &&
3900 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003901 ret = wl1271_acx_set_ht_capabilities(wl,
3902 &sta_ht_cap,
3903 true,
Eliad Peller154da672011-10-05 11:55:53 +02003904 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003905 if (ret < 0) {
3906 wl1271_warning("Set ht cap true failed %d",
3907 ret);
3908 goto out;
3909 }
3910 }
3911 /* handle new association without HT and disassociation */
3912 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003913 ret = wl1271_acx_set_ht_capabilities(wl,
3914 &sta_ht_cap,
3915 false,
Eliad Peller154da672011-10-05 11:55:53 +02003916 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003917 if (ret < 0) {
3918 wl1271_warning("Set ht cap false failed %d",
3919 ret);
3920 goto out;
3921 }
3922 }
3923 }
3924
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003925 /* Handle HT information change. Done after join. */
3926 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003927 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003928 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003929 bss_conf->ht_operation_mode);
3930 if (ret < 0) {
3931 wl1271_warning("Set ht information failed %d", ret);
3932 goto out;
3933 }
3934 }
3935
Arik Nemtsove78a2872010-10-16 19:07:21 +02003936out:
3937 return;
3938}
3939
3940static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3941 struct ieee80211_vif *vif,
3942 struct ieee80211_bss_conf *bss_conf,
3943 u32 changed)
3944{
3945 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003946 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3947 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003948 int ret;
3949
3950 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3951 (int)changed);
3952
3953 mutex_lock(&wl->mutex);
3954
3955 if (unlikely(wl->state == WL1271_STATE_OFF))
3956 goto out;
3957
Eliad Peller10c8cd02011-10-10 10:13:06 +02003958 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3959 goto out;
3960
Ido Yariva6208652011-03-01 15:14:41 +02003961 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003962 if (ret < 0)
3963 goto out;
3964
3965 if (is_ap)
3966 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3967 else
3968 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3969
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003970 wl1271_ps_elp_sleep(wl);
3971
3972out:
3973 mutex_unlock(&wl->mutex);
3974}
3975
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003976static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3977 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003978 const struct ieee80211_tx_queue_params *params)
3979{
3980 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003981 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003982 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003983 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003984
3985 mutex_lock(&wl->mutex);
3986
3987 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3988
Kalle Valo4695dc92010-03-18 12:26:38 +02003989 if (params->uapsd)
3990 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3991 else
3992 ps_scheme = CONF_PS_SCHEME_LEGACY;
3993
Arik Nemtsov488fc542010-10-16 20:33:45 +02003994 if (wl->state == WL1271_STATE_OFF) {
3995 /*
3996 * If the state is off, the parameters will be recorded and
3997 * configured on init. This happens in AP-mode.
3998 */
3999 struct conf_tx_ac_category *conf_ac =
4000 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
4001 struct conf_tx_tid *conf_tid =
4002 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
4003
4004 conf_ac->ac = wl1271_tx_get_queue(queue);
4005 conf_ac->cw_min = (u8)params->cw_min;
4006 conf_ac->cw_max = params->cw_max;
4007 conf_ac->aifsn = params->aifs;
4008 conf_ac->tx_op_limit = params->txop << 5;
4009
4010 conf_tid->queue_id = wl1271_tx_get_queue(queue);
4011 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
4012 conf_tid->tsid = wl1271_tx_get_queue(queue);
4013 conf_tid->ps_scheme = ps_scheme;
4014 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4015 conf_tid->apsd_conf[0] = 0;
4016 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 goto out;
4018 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004019
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004020 ret = wl1271_ps_elp_wakeup(wl);
4021 if (ret < 0)
4022 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004023
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004024 /*
4025 * the txop is confed in units of 32us by the mac80211,
4026 * we need us
4027 */
Eliad Peller0603d892011-10-05 11:55:51 +02004028 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004029 params->cw_min, params->cw_max,
4030 params->aifs, params->txop << 5);
4031 if (ret < 0)
4032 goto out_sleep;
4033
Eliad Peller0603d892011-10-05 11:55:51 +02004034 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004035 CONF_CHANNEL_TYPE_EDCF,
4036 wl1271_tx_get_queue(queue),
4037 ps_scheme, CONF_ACK_POLICY_LEGACY,
4038 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004039
4040out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004041 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004042
4043out:
4044 mutex_unlock(&wl->mutex);
4045
4046 return ret;
4047}
4048
Eliad Peller37a41b42011-09-21 14:06:11 +03004049static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4050 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004051{
4052
4053 struct wl1271 *wl = hw->priv;
4054 u64 mactime = ULLONG_MAX;
4055 int ret;
4056
4057 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4058
4059 mutex_lock(&wl->mutex);
4060
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004061 if (unlikely(wl->state == WL1271_STATE_OFF))
4062 goto out;
4063
Ido Yariva6208652011-03-01 15:14:41 +02004064 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004065 if (ret < 0)
4066 goto out;
4067
4068 ret = wl1271_acx_tsf_info(wl, &mactime);
4069 if (ret < 0)
4070 goto out_sleep;
4071
4072out_sleep:
4073 wl1271_ps_elp_sleep(wl);
4074
4075out:
4076 mutex_unlock(&wl->mutex);
4077 return mactime;
4078}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004079
John W. Linvilleece550d2010-07-28 16:41:06 -04004080static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4081 struct survey_info *survey)
4082{
4083 struct wl1271 *wl = hw->priv;
4084 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004085
John W. Linvilleece550d2010-07-28 16:41:06 -04004086 if (idx != 0)
4087 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004088
John W. Linvilleece550d2010-07-28 16:41:06 -04004089 survey->channel = conf->channel;
4090 survey->filled = SURVEY_INFO_NOISE_DBM;
4091 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004092
John W. Linvilleece550d2010-07-28 16:41:06 -04004093 return 0;
4094}
4095
Arik Nemtsov409622e2011-02-23 00:22:29 +02004096static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004097 struct wl12xx_vif *wlvif,
4098 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004099{
4100 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004101 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004102
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004103
4104 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105 wl1271_warning("could not allocate HLID - too much stations");
4106 return -EBUSY;
4107 }
4108
4109 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004110 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4111 if (ret < 0) {
4112 wl1271_warning("could not allocate HLID - too many links");
4113 return -EBUSY;
4114 }
4115
4116 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004117 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004118 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119 return 0;
4120}
4121
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004123{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004124 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004125 return;
4126
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004127 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004128 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004129 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004130 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004131 __clear_bit(hlid, &wl->ap_ps_map);
4132 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004133 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004134 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004135}
4136
4137static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4138 struct ieee80211_vif *vif,
4139 struct ieee80211_sta *sta)
4140{
4141 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004142 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004143 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004144 int ret = 0;
4145 u8 hlid;
4146
4147 mutex_lock(&wl->mutex);
4148
4149 if (unlikely(wl->state == WL1271_STATE_OFF))
4150 goto out;
4151
Eliad Peller536129c2011-10-05 11:55:45 +02004152 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004153 goto out;
4154
4155 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4156
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004157 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004158 if (ret < 0)
4159 goto out;
4160
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004161 wl_sta = (struct wl1271_station *)sta->drv_priv;
4162 hlid = wl_sta->hlid;
4163
Ido Yariva6208652011-03-01 15:14:41 +02004164 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004166 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004167
Eliad Peller1b92f152011-10-10 10:13:09 +02004168 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004169 if (ret < 0)
4170 goto out_sleep;
4171
Eliad Pellerb67476e2011-08-14 13:17:23 +03004172 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4173 if (ret < 0)
4174 goto out_sleep;
4175
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004176 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4177 if (ret < 0)
4178 goto out_sleep;
4179
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004180out_sleep:
4181 wl1271_ps_elp_sleep(wl);
4182
Arik Nemtsov409622e2011-02-23 00:22:29 +02004183out_free_sta:
4184 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004185 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004186
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004187out:
4188 mutex_unlock(&wl->mutex);
4189 return ret;
4190}
4191
4192static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4193 struct ieee80211_vif *vif,
4194 struct ieee80211_sta *sta)
4195{
4196 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004197 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004198 struct wl1271_station *wl_sta;
4199 int ret = 0, id;
4200
4201 mutex_lock(&wl->mutex);
4202
4203 if (unlikely(wl->state == WL1271_STATE_OFF))
4204 goto out;
4205
Eliad Peller536129c2011-10-05 11:55:45 +02004206 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004207 goto out;
4208
4209 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4210
4211 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004212 id = wl_sta->hlid;
4213 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004214 goto out;
4215
Ido Yariva6208652011-03-01 15:14:41 +02004216 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004217 if (ret < 0)
4218 goto out;
4219
Eliad Pellerc690ec82011-08-14 13:17:07 +03004220 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004221 if (ret < 0)
4222 goto out_sleep;
4223
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004224 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004225
4226out_sleep:
4227 wl1271_ps_elp_sleep(wl);
4228
4229out:
4230 mutex_unlock(&wl->mutex);
4231 return ret;
4232}
4233
Luciano Coelho4623ec72011-03-21 19:26:41 +02004234static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4235 struct ieee80211_vif *vif,
4236 enum ieee80211_ampdu_mlme_action action,
4237 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4238 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004239{
4240 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004241 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004242 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004243 u8 hlid, *ba_bitmap;
4244
4245 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4246 tid);
4247
4248 /* sanity check - the fields in FW are only 8bits wide */
4249 if (WARN_ON(tid > 0xFF))
4250 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004251
4252 mutex_lock(&wl->mutex);
4253
4254 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4255 ret = -EAGAIN;
4256 goto out;
4257 }
4258
Eliad Peller536129c2011-10-05 11:55:45 +02004259 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004260 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004261 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004262 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004263 struct wl1271_station *wl_sta;
4264
4265 wl_sta = (struct wl1271_station *)sta->drv_priv;
4266 hlid = wl_sta->hlid;
4267 ba_bitmap = &wl->links[hlid].ba_bitmap;
4268 } else {
4269 ret = -EINVAL;
4270 goto out;
4271 }
4272
Ido Yariva6208652011-03-01 15:14:41 +02004273 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004274 if (ret < 0)
4275 goto out;
4276
Shahar Levi70559a02011-05-22 16:10:22 +03004277 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4278 tid, action);
4279
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004280 switch (action) {
4281 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004282 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004283 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004284 break;
4285 }
4286
4287 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4288 ret = -EBUSY;
4289 wl1271_error("exceeded max RX BA sessions");
4290 break;
4291 }
4292
4293 if (*ba_bitmap & BIT(tid)) {
4294 ret = -EINVAL;
4295 wl1271_error("cannot enable RX BA session on active "
4296 "tid: %d", tid);
4297 break;
4298 }
4299
4300 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4301 hlid);
4302 if (!ret) {
4303 *ba_bitmap |= BIT(tid);
4304 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004305 }
4306 break;
4307
4308 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004309 if (!(*ba_bitmap & BIT(tid))) {
4310 ret = -EINVAL;
4311 wl1271_error("no active RX BA session on tid: %d",
4312 tid);
4313 break;
4314 }
4315
4316 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4317 hlid);
4318 if (!ret) {
4319 *ba_bitmap &= ~BIT(tid);
4320 wl->ba_rx_session_count--;
4321 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004322 break;
4323
4324 /*
4325 * The BA initiator session management in FW independently.
4326 * Falling break here on purpose for all TX APDU commands.
4327 */
4328 case IEEE80211_AMPDU_TX_START:
4329 case IEEE80211_AMPDU_TX_STOP:
4330 case IEEE80211_AMPDU_TX_OPERATIONAL:
4331 ret = -EINVAL;
4332 break;
4333
4334 default:
4335 wl1271_error("Incorrect ampdu action id=%x\n", action);
4336 ret = -EINVAL;
4337 }
4338
4339 wl1271_ps_elp_sleep(wl);
4340
4341out:
4342 mutex_unlock(&wl->mutex);
4343
4344 return ret;
4345}
4346
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004347static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4348 struct ieee80211_vif *vif,
4349 const struct cfg80211_bitrate_mask *mask)
4350{
Eliad Peller83587502011-10-10 10:12:53 +02004351 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004352 struct wl1271 *wl = hw->priv;
4353 int i;
4354
4355 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4356 mask->control[NL80211_BAND_2GHZ].legacy,
4357 mask->control[NL80211_BAND_5GHZ].legacy);
4358
4359 mutex_lock(&wl->mutex);
4360
4361 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004362 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004363 wl1271_tx_enabled_rates_get(wl,
4364 mask->control[i].legacy,
4365 i);
4366 mutex_unlock(&wl->mutex);
4367
4368 return 0;
4369}
4370
Shahar Levi6d158ff2011-09-08 13:01:33 +03004371static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4372 struct ieee80211_channel_switch *ch_switch)
4373{
4374 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004375 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004376 int ret;
4377
4378 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4379
4380 mutex_lock(&wl->mutex);
4381
4382 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004383 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4384 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4385 ieee80211_chswitch_done(vif, false);
4386 }
4387 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004388 }
4389
4390 ret = wl1271_ps_elp_wakeup(wl);
4391 if (ret < 0)
4392 goto out;
4393
Eliad Peller52630c52011-10-10 10:13:08 +02004394 /* TODO: change mac80211 to pass vif as param */
4395 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4396 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004397
Eliad Peller52630c52011-10-10 10:13:08 +02004398 if (!ret)
4399 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4400 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004401
4402 wl1271_ps_elp_sleep(wl);
4403
4404out:
4405 mutex_unlock(&wl->mutex);
4406}
4407
Arik Nemtsov33437892011-04-26 23:35:39 +03004408static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4409{
4410 struct wl1271 *wl = hw->priv;
4411 bool ret = false;
4412
4413 mutex_lock(&wl->mutex);
4414
4415 if (unlikely(wl->state == WL1271_STATE_OFF))
4416 goto out;
4417
4418 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004419 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004420out:
4421 mutex_unlock(&wl->mutex);
4422
4423 return ret;
4424}
4425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426/* can't be const, mac80211 writes to this */
4427static struct ieee80211_rate wl1271_rates[] = {
4428 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004429 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4430 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4435 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4439 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004440 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4441 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004442 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4443 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004456 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4457 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004459 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004461 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004462 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004465 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467};
4468
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004469/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004471 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004472 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004473 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4474 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4475 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004476 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004477 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4478 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4479 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004480 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004481 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4482 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4483 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004484 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004485};
4486
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004487/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004488static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004489 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004490 7, /* CONF_HW_RXTX_RATE_MCS7 */
4491 6, /* CONF_HW_RXTX_RATE_MCS6 */
4492 5, /* CONF_HW_RXTX_RATE_MCS5 */
4493 4, /* CONF_HW_RXTX_RATE_MCS4 */
4494 3, /* CONF_HW_RXTX_RATE_MCS3 */
4495 2, /* CONF_HW_RXTX_RATE_MCS2 */
4496 1, /* CONF_HW_RXTX_RATE_MCS1 */
4497 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004498
4499 11, /* CONF_HW_RXTX_RATE_54 */
4500 10, /* CONF_HW_RXTX_RATE_48 */
4501 9, /* CONF_HW_RXTX_RATE_36 */
4502 8, /* CONF_HW_RXTX_RATE_24 */
4503
4504 /* TI-specific rate */
4505 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4506
4507 7, /* CONF_HW_RXTX_RATE_18 */
4508 6, /* CONF_HW_RXTX_RATE_12 */
4509 3, /* CONF_HW_RXTX_RATE_11 */
4510 5, /* CONF_HW_RXTX_RATE_9 */
4511 4, /* CONF_HW_RXTX_RATE_6 */
4512 2, /* CONF_HW_RXTX_RATE_5_5 */
4513 1, /* CONF_HW_RXTX_RATE_2 */
4514 0 /* CONF_HW_RXTX_RATE_1 */
4515};
4516
Shahar Levie8b03a22010-10-13 16:09:39 +02004517/* 11n STA capabilities */
4518#define HW_RX_HIGHEST_RATE 72
4519
Shahar Levi00d20102010-11-08 11:20:10 +00004520#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004521 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4522 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004523 .ht_supported = true, \
4524 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4525 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4526 .mcs = { \
4527 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4528 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4529 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4530 }, \
4531}
4532
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004533/* can't be const, mac80211 writes to this */
4534static struct ieee80211_supported_band wl1271_band_2ghz = {
4535 .channels = wl1271_channels,
4536 .n_channels = ARRAY_SIZE(wl1271_channels),
4537 .bitrates = wl1271_rates,
4538 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004539 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004540};
4541
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004542/* 5 GHz data rates for WL1273 */
4543static struct ieee80211_rate wl1271_rates_5ghz[] = {
4544 { .bitrate = 60,
4545 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4547 { .bitrate = 90,
4548 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4550 { .bitrate = 120,
4551 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4553 { .bitrate = 180,
4554 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4556 { .bitrate = 240,
4557 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4558 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4559 { .bitrate = 360,
4560 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4562 { .bitrate = 480,
4563 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4565 { .bitrate = 540,
4566 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4568};
4569
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004570/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004571static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004572 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4573 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4574 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4575 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4576 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4577 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4578 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4579 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4580 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4581 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4582 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4583 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4584 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4585 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4586 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4587 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4588 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4589 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4590 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4591 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4592 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4593 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4594 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4595 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4596 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4597 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4598 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4599 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4600 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4601 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4602 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4603 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4604 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4605 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004606};
4607
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004608/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004609static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004610 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004611 7, /* CONF_HW_RXTX_RATE_MCS7 */
4612 6, /* CONF_HW_RXTX_RATE_MCS6 */
4613 5, /* CONF_HW_RXTX_RATE_MCS5 */
4614 4, /* CONF_HW_RXTX_RATE_MCS4 */
4615 3, /* CONF_HW_RXTX_RATE_MCS3 */
4616 2, /* CONF_HW_RXTX_RATE_MCS2 */
4617 1, /* CONF_HW_RXTX_RATE_MCS1 */
4618 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004619
4620 7, /* CONF_HW_RXTX_RATE_54 */
4621 6, /* CONF_HW_RXTX_RATE_48 */
4622 5, /* CONF_HW_RXTX_RATE_36 */
4623 4, /* CONF_HW_RXTX_RATE_24 */
4624
4625 /* TI-specific rate */
4626 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4627
4628 3, /* CONF_HW_RXTX_RATE_18 */
4629 2, /* CONF_HW_RXTX_RATE_12 */
4630 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4631 1, /* CONF_HW_RXTX_RATE_9 */
4632 0, /* CONF_HW_RXTX_RATE_6 */
4633 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4634 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4635 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4636};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004637
4638static struct ieee80211_supported_band wl1271_band_5ghz = {
4639 .channels = wl1271_channels_5ghz,
4640 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4641 .bitrates = wl1271_rates_5ghz,
4642 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004643 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004644};
4645
Tobias Klausera0ea9492010-05-20 10:38:11 +02004646static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004647 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4648 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4649};
4650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004651static const struct ieee80211_ops wl1271_ops = {
4652 .start = wl1271_op_start,
4653 .stop = wl1271_op_stop,
4654 .add_interface = wl1271_op_add_interface,
4655 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004656#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004657 .suspend = wl1271_op_suspend,
4658 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004659#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004661 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004662 .configure_filter = wl1271_op_configure_filter,
4663 .tx = wl1271_op_tx,
4664 .set_key = wl1271_op_set_key,
4665 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004666 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004667 .sched_scan_start = wl1271_op_sched_scan_start,
4668 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004669 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004670 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004671 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004672 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004673 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004674 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004675 .sta_add = wl1271_op_sta_add,
4676 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004677 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004678 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004679 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004680 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004681 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004682};
4683
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004684
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004685u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004686{
4687 u8 idx;
4688
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004689 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004690
4691 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4692 wl1271_error("Illegal RX rate from HW: %d", rate);
4693 return 0;
4694 }
4695
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004696 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004697 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4698 wl1271_error("Unsupported RX rate from HW: %d", rate);
4699 return 0;
4700 }
4701
4702 return idx;
4703}
4704
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004705static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4706 struct device_attribute *attr,
4707 char *buf)
4708{
4709 struct wl1271 *wl = dev_get_drvdata(dev);
4710 ssize_t len;
4711
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004712 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004713
4714 mutex_lock(&wl->mutex);
4715 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4716 wl->sg_enabled);
4717 mutex_unlock(&wl->mutex);
4718
4719 return len;
4720
4721}
4722
4723static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4724 struct device_attribute *attr,
4725 const char *buf, size_t count)
4726{
4727 struct wl1271 *wl = dev_get_drvdata(dev);
4728 unsigned long res;
4729 int ret;
4730
Luciano Coelho6277ed62011-04-01 17:49:54 +03004731 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004732 if (ret < 0) {
4733 wl1271_warning("incorrect value written to bt_coex_mode");
4734 return count;
4735 }
4736
4737 mutex_lock(&wl->mutex);
4738
4739 res = !!res;
4740
4741 if (res == wl->sg_enabled)
4742 goto out;
4743
4744 wl->sg_enabled = res;
4745
4746 if (wl->state == WL1271_STATE_OFF)
4747 goto out;
4748
Ido Yariva6208652011-03-01 15:14:41 +02004749 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004750 if (ret < 0)
4751 goto out;
4752
4753 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4754 wl1271_ps_elp_sleep(wl);
4755
4756 out:
4757 mutex_unlock(&wl->mutex);
4758 return count;
4759}
4760
4761static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4762 wl1271_sysfs_show_bt_coex_state,
4763 wl1271_sysfs_store_bt_coex_state);
4764
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004765static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4766 struct device_attribute *attr,
4767 char *buf)
4768{
4769 struct wl1271 *wl = dev_get_drvdata(dev);
4770 ssize_t len;
4771
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004772 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004773
4774 mutex_lock(&wl->mutex);
4775 if (wl->hw_pg_ver >= 0)
4776 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4777 else
4778 len = snprintf(buf, len, "n/a\n");
4779 mutex_unlock(&wl->mutex);
4780
4781 return len;
4782}
4783
Gery Kahn6f07b722011-07-18 14:21:49 +03004784static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004785 wl1271_sysfs_show_hw_pg_ver, NULL);
4786
Ido Yariv95dac04f2011-06-06 14:57:06 +03004787static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4788 struct bin_attribute *bin_attr,
4789 char *buffer, loff_t pos, size_t count)
4790{
4791 struct device *dev = container_of(kobj, struct device, kobj);
4792 struct wl1271 *wl = dev_get_drvdata(dev);
4793 ssize_t len;
4794 int ret;
4795
4796 ret = mutex_lock_interruptible(&wl->mutex);
4797 if (ret < 0)
4798 return -ERESTARTSYS;
4799
4800 /* Let only one thread read the log at a time, blocking others */
4801 while (wl->fwlog_size == 0) {
4802 DEFINE_WAIT(wait);
4803
4804 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4805 &wait,
4806 TASK_INTERRUPTIBLE);
4807
4808 if (wl->fwlog_size != 0) {
4809 finish_wait(&wl->fwlog_waitq, &wait);
4810 break;
4811 }
4812
4813 mutex_unlock(&wl->mutex);
4814
4815 schedule();
4816 finish_wait(&wl->fwlog_waitq, &wait);
4817
4818 if (signal_pending(current))
4819 return -ERESTARTSYS;
4820
4821 ret = mutex_lock_interruptible(&wl->mutex);
4822 if (ret < 0)
4823 return -ERESTARTSYS;
4824 }
4825
4826 /* Check if the fwlog is still valid */
4827 if (wl->fwlog_size < 0) {
4828 mutex_unlock(&wl->mutex);
4829 return 0;
4830 }
4831
4832 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4833 len = min(count, (size_t)wl->fwlog_size);
4834 wl->fwlog_size -= len;
4835 memcpy(buffer, wl->fwlog, len);
4836
4837 /* Make room for new messages */
4838 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4839
4840 mutex_unlock(&wl->mutex);
4841
4842 return len;
4843}
4844
4845static struct bin_attribute fwlog_attr = {
4846 .attr = {.name = "fwlog", .mode = S_IRUSR},
4847 .read = wl1271_sysfs_read_fwlog,
4848};
4849
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004850static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004851{
4852 int ret;
4853
4854 if (wl->mac80211_registered)
4855 return 0;
4856
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004857 ret = wl1271_fetch_nvs(wl);
4858 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004859 /* NOTE: The wl->nvs->nvs element must be first, in
4860 * order to simplify the casting, we assume it is at
4861 * the beginning of the wl->nvs structure.
4862 */
4863 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004864
4865 wl->mac_addr[0] = nvs_ptr[11];
4866 wl->mac_addr[1] = nvs_ptr[10];
4867 wl->mac_addr[2] = nvs_ptr[6];
4868 wl->mac_addr[3] = nvs_ptr[5];
4869 wl->mac_addr[4] = nvs_ptr[4];
4870 wl->mac_addr[5] = nvs_ptr[3];
4871 }
4872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004873 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4874
4875 ret = ieee80211_register_hw(wl->hw);
4876 if (ret < 0) {
4877 wl1271_error("unable to register mac80211 hw: %d", ret);
4878 return ret;
4879 }
4880
4881 wl->mac80211_registered = true;
4882
Eliad Pellerd60080a2010-11-24 12:53:16 +02004883 wl1271_debugfs_init(wl);
4884
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004885 register_netdevice_notifier(&wl1271_dev_notifier);
4886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004887 wl1271_notice("loaded");
4888
4889 return 0;
4890}
4891
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004892static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004893{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004894 if (wl->state == WL1271_STATE_PLT)
4895 __wl1271_plt_stop(wl);
4896
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004897 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004898 ieee80211_unregister_hw(wl->hw);
4899 wl->mac80211_registered = false;
4900
4901}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004902
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004903static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004905 static const u32 cipher_suites[] = {
4906 WLAN_CIPHER_SUITE_WEP40,
4907 WLAN_CIPHER_SUITE_WEP104,
4908 WLAN_CIPHER_SUITE_TKIP,
4909 WLAN_CIPHER_SUITE_CCMP,
4910 WL1271_CIPHER_SUITE_GEM,
4911 };
4912
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004913 /* The tx descriptor buffer and the TKIP space. */
4914 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4915 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004916
4917 /* unit us */
4918 /* FIXME: find a proper value */
4919 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004920 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004921
4922 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004923 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004924 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004925 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004926 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004927 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004928 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004929 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004930 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004931 IEEE80211_HW_AP_LINK_PS |
4932 IEEE80211_HW_AMPDU_AGGREGATION |
4933 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004934
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004935 wl->hw->wiphy->cipher_suites = cipher_suites;
4936 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4937
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004938 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004939 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4940 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004941 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004942 wl->hw->wiphy->max_sched_scan_ssids = 16;
4943 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004944 /*
4945 * Maximum length of elements in scanning probe request templates
4946 * should be the maximum length possible for a template, without
4947 * the IEEE80211 header of the template
4948 */
Eliad Peller154037d2011-08-14 13:17:12 +03004949 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004950 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004951
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004952 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4953 sizeof(struct ieee80211_header);
4954
Eliad Peller1ec23f72011-08-25 14:26:54 +03004955 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4956
Luciano Coelho4a31c112011-03-21 23:16:14 +02004957 /* make sure all our channels fit in the scanned_ch bitmask */
4958 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4959 ARRAY_SIZE(wl1271_channels_5ghz) >
4960 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004961 /*
4962 * We keep local copies of the band structs because we need to
4963 * modify them on a per-device basis.
4964 */
4965 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4966 sizeof(wl1271_band_2ghz));
4967 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4968 sizeof(wl1271_band_5ghz));
4969
4970 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4971 &wl->bands[IEEE80211_BAND_2GHZ];
4972 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4973 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004974
Kalle Valo12bd8942010-03-18 12:26:33 +02004975 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004976 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004977
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004978 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4979
Felipe Balbia390e852011-10-06 10:07:44 +03004980 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004982 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004983 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004984
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004985 wl->hw->max_rx_aggregation_subframes = 8;
4986
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987 return 0;
4988}
4989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004991
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004992static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004993{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004995 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004996 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004997 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004998 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005000 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5003 if (!hw) {
5004 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005005 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005006 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005007 }
5008
Julia Lawall929ebd32010-05-15 23:16:39 +02005009 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005010 if (!plat_dev) {
5011 wl1271_error("could not allocate platform_device");
5012 ret = -ENOMEM;
5013 goto err_plat_alloc;
5014 }
5015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005016 wl = hw->priv;
5017 memset(wl, 0, sizeof(*wl));
5018
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005019 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005020 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005023 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005024
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005025 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005026 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005027 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5028
Ido Yariva6208652011-03-01 15:14:41 +02005029 skb_queue_head_init(&wl->deferred_rx_queue);
5030 skb_queue_head_init(&wl->deferred_tx_queue);
5031
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005032 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005033 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005034 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5035 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5036 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005037
Eliad Peller92ef8962011-06-07 12:50:46 +03005038 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5039 if (!wl->freezable_wq) {
5040 ret = -ENOMEM;
5041 goto err_hw;
5042 }
5043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005044 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005046 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005047 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005048 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005049 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005050 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005051 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005052 wl->ap_ps_map = 0;
5053 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005054 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005055 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005056 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005057 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005058 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005059 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005060 wl->fwlog_size = 0;
5061 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005062
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005063 /* The system link is always allocated */
5064 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5065
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005066 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005067 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005068 wl->tx_frames[i] = NULL;
5069
5070 spin_lock_init(&wl->wl_lock);
5071
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005072 wl->state = WL1271_STATE_OFF;
5073 mutex_init(&wl->mutex);
5074
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005075 /* Apply default driver configuration. */
5076 wl1271_conf_init(wl);
5077
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005078 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5079 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5080 if (!wl->aggr_buf) {
5081 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005082 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005083 }
5084
Ido Yariv990f5de2011-03-31 10:06:59 +02005085 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5086 if (!wl->dummy_packet) {
5087 ret = -ENOMEM;
5088 goto err_aggr;
5089 }
5090
Ido Yariv95dac04f2011-06-06 14:57:06 +03005091 /* Allocate one page for the FW log */
5092 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5093 if (!wl->fwlog) {
5094 ret = -ENOMEM;
5095 goto err_dummy_packet;
5096 }
5097
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005098 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005099 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005100 if (ret) {
5101 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03005102 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005103 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005104 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005105
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005106 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005107 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005108 if (ret < 0) {
5109 wl1271_error("failed to create sysfs file bt_coex_state");
5110 goto err_platform;
5111 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005112
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005113 /* Create sysfs file to get HW PG version */
5114 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5115 if (ret < 0) {
5116 wl1271_error("failed to create sysfs file hw_pg_ver");
5117 goto err_bt_coex_state;
5118 }
5119
Ido Yariv95dac04f2011-06-06 14:57:06 +03005120 /* Create sysfs file for the FW log */
5121 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
5122 if (ret < 0) {
5123 wl1271_error("failed to create sysfs file fwlog");
5124 goto err_hw_pg_ver;
5125 }
5126
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005127 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005128
Ido Yariv95dac04f2011-06-06 14:57:06 +03005129err_hw_pg_ver:
5130 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5131
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005132err_bt_coex_state:
5133 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
5134
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005135err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005136 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005137
Ido Yariv95dac04f2011-06-06 14:57:06 +03005138err_fwlog:
5139 free_page((unsigned long)wl->fwlog);
5140
Ido Yariv990f5de2011-03-31 10:06:59 +02005141err_dummy_packet:
5142 dev_kfree_skb(wl->dummy_packet);
5143
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005144err_aggr:
5145 free_pages((unsigned long)wl->aggr_buf, order);
5146
Eliad Peller92ef8962011-06-07 12:50:46 +03005147err_wq:
5148 destroy_workqueue(wl->freezable_wq);
5149
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005150err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005151 wl1271_debugfs_exit(wl);
5152 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005153
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005154err_plat_alloc:
5155 ieee80211_free_hw(hw);
5156
5157err_hw_alloc:
5158
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005159 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005160}
5161
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005162static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005163{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005164 /* Unblock any fwlog readers */
5165 mutex_lock(&wl->mutex);
5166 wl->fwlog_size = -1;
5167 wake_up_interruptible_all(&wl->fwlog_waitq);
5168 mutex_unlock(&wl->mutex);
5169
5170 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005171
5172 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5173
5174 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005175 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005176 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005177 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005178 free_pages((unsigned long)wl->aggr_buf,
5179 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005180 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005181
5182 wl1271_debugfs_exit(wl);
5183
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005184 vfree(wl->fw);
5185 wl->fw = NULL;
5186 kfree(wl->nvs);
5187 wl->nvs = NULL;
5188
5189 kfree(wl->fw_status);
5190 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005191 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005192
5193 ieee80211_free_hw(wl->hw);
5194
5195 return 0;
5196}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005197
Felipe Balbia390e852011-10-06 10:07:44 +03005198static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5199{
5200 struct wl1271 *wl = cookie;
5201 unsigned long flags;
5202
5203 wl1271_debug(DEBUG_IRQ, "IRQ");
5204
5205 /* complete the ELP completion */
5206 spin_lock_irqsave(&wl->wl_lock, flags);
5207 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5208 if (wl->elp_compl) {
5209 complete(wl->elp_compl);
5210 wl->elp_compl = NULL;
5211 }
5212
5213 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5214 /* don't enqueue a work right now. mark it as pending */
5215 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5216 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5217 disable_irq_nosync(wl->irq);
5218 pm_wakeup_event(wl->dev, 0);
5219 spin_unlock_irqrestore(&wl->wl_lock, flags);
5220 return IRQ_HANDLED;
5221 }
5222 spin_unlock_irqrestore(&wl->wl_lock, flags);
5223
5224 return IRQ_WAKE_THREAD;
5225}
5226
Felipe Balbice2a2172011-10-05 14:12:55 +03005227static int __devinit wl12xx_probe(struct platform_device *pdev)
5228{
Felipe Balbia390e852011-10-06 10:07:44 +03005229 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5230 struct ieee80211_hw *hw;
5231 struct wl1271 *wl;
5232 unsigned long irqflags;
5233 int ret = -ENODEV;
5234
5235 hw = wl1271_alloc_hw();
5236 if (IS_ERR(hw)) {
5237 wl1271_error("can't allocate hw");
5238 ret = PTR_ERR(hw);
5239 goto out;
5240 }
5241
5242 wl = hw->priv;
5243 wl->irq = platform_get_irq(pdev, 0);
5244 wl->ref_clock = pdata->board_ref_clock;
5245 wl->tcxo_clock = pdata->board_tcxo_clock;
5246 wl->platform_quirks = pdata->platform_quirks;
5247 wl->set_power = pdata->set_power;
5248 wl->dev = &pdev->dev;
5249 wl->if_ops = pdata->ops;
5250
5251 platform_set_drvdata(pdev, wl);
5252
5253 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5254 irqflags = IRQF_TRIGGER_RISING;
5255 else
5256 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5257
5258 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5259 irqflags,
5260 pdev->name, wl);
5261 if (ret < 0) {
5262 wl1271_error("request_irq() failed: %d", ret);
5263 goto out_free_hw;
5264 }
5265
5266 ret = enable_irq_wake(wl->irq);
5267 if (!ret) {
5268 wl->irq_wake_enabled = true;
5269 device_init_wakeup(wl->dev, 1);
5270 if (pdata->pwr_in_suspend)
5271 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5272
5273 }
5274 disable_irq(wl->irq);
5275
5276 ret = wl1271_init_ieee80211(wl);
5277 if (ret)
5278 goto out_irq;
5279
5280 ret = wl1271_register_hw(wl);
5281 if (ret)
5282 goto out_irq;
5283
Felipe Balbice2a2172011-10-05 14:12:55 +03005284 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005285
5286out_irq:
5287 free_irq(wl->irq, wl);
5288
5289out_free_hw:
5290 wl1271_free_hw(wl);
5291
5292out:
5293 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005294}
5295
5296static int __devexit wl12xx_remove(struct platform_device *pdev)
5297{
Felipe Balbia390e852011-10-06 10:07:44 +03005298 struct wl1271 *wl = platform_get_drvdata(pdev);
5299
5300 if (wl->irq_wake_enabled) {
5301 device_init_wakeup(wl->dev, 0);
5302 disable_irq_wake(wl->irq);
5303 }
5304 wl1271_unregister_hw(wl);
5305 free_irq(wl->irq, wl);
5306 wl1271_free_hw(wl);
5307
Felipe Balbice2a2172011-10-05 14:12:55 +03005308 return 0;
5309}
5310
5311static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
5312 { "wl12xx-sdio", 0 },
5313 { "wl12xx-spi", 0 },
5314 { } /* Terminating Entry */
5315};
5316MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5317
5318static struct platform_driver wl12xx_driver = {
5319 .probe = wl12xx_probe,
5320 .remove = __devexit_p(wl12xx_remove),
5321 .id_table = wl12xx_id_table,
5322 .driver = {
5323 .name = "wl12xx",
5324 .owner = THIS_MODULE,
5325 }
5326};
5327
5328static int __init wl12xx_init(void)
5329{
5330 return platform_driver_register(&wl12xx_driver);
5331}
5332module_init(wl12xx_init);
5333
5334static void __exit wl12xx_exit(void)
5335{
5336 platform_driver_unregister(&wl12xx_driver);
5337}
5338module_exit(wl12xx_exit);
5339
Guy Eilam491bbd62011-01-12 10:33:29 +01005340u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005341EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005342module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005343MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5344
Ido Yariv95dac04f2011-06-06 14:57:06 +03005345module_param_named(fwlog, fwlog_param, charp, 0);
5346MODULE_PARM_DESC(keymap,
5347 "FW logger options: continuous, ondemand, dbgpins or disable");
5348
Eliad Peller2a5bff02011-08-25 18:10:59 +03005349module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5350MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5351
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005352MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005353MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005354MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");