blob: 195dcbdf1fc7270f66239581d0f0c994ba5f9836 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
380 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200381static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200382
383
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200384static void wl1271_device_release(struct device *dev)
385{
386
387}
388
389static struct platform_device wl1271_device = {
390 .name = "wl1271",
391 .id = -1,
392
393 /* device model insists to have a release function */
394 .dev = {
395 .release = wl1271_device_release,
396 },
397};
398
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200399static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300400static LIST_HEAD(wl_list);
401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
403{
404 int ret;
405 if (operstate != IF_OPER_UP)
406 return 0;
407
408 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
409 return 0;
410
Eliad Pellerb67476e2011-08-14 13:17:23 +0300411 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300412 if (ret < 0)
413 return ret;
414
Eliad Peller251c1772011-08-14 13:17:17 +0300415 wl12xx_croc(wl, wl->role_id);
416
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300417 wl1271_info("Association completed.");
418 return 0;
419}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
421 void *arg)
422{
423 struct net_device *dev = arg;
424 struct wireless_dev *wdev;
425 struct wiphy *wiphy;
426 struct ieee80211_hw *hw;
427 struct wl1271 *wl;
428 struct wl1271 *wl_temp;
429 int ret = 0;
430
431 /* Check that this notification is for us. */
432 if (what != NETDEV_CHANGE)
433 return NOTIFY_DONE;
434
435 wdev = dev->ieee80211_ptr;
436 if (wdev == NULL)
437 return NOTIFY_DONE;
438
439 wiphy = wdev->wiphy;
440 if (wiphy == NULL)
441 return NOTIFY_DONE;
442
443 hw = wiphy_priv(wiphy);
444 if (hw == NULL)
445 return NOTIFY_DONE;
446
447 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200448 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300449 list_for_each_entry(wl, &wl_list, list) {
450 if (wl == wl_temp)
451 break;
452 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200453 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 if (wl != wl_temp)
455 return NOTIFY_DONE;
456
457 mutex_lock(&wl->mutex);
458
459 if (wl->state == WL1271_STATE_OFF)
460 goto out;
461
462 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
463 goto out;
464
Ido Yariva6208652011-03-01 15:14:41 +0200465 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300466 if (ret < 0)
467 goto out;
468
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300469 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300470
471 wl1271_ps_elp_sleep(wl);
472
473out:
474 mutex_unlock(&wl->mutex);
475
476 return NOTIFY_OK;
477}
478
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100479static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200480 struct regulatory_request *request)
481{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100482 struct ieee80211_supported_band *band;
483 struct ieee80211_channel *ch;
484 int i;
485
486 band = wiphy->bands[IEEE80211_BAND_5GHZ];
487 for (i = 0; i < band->n_channels; i++) {
488 ch = &band->channels[i];
489 if (ch->flags & IEEE80211_CHAN_DISABLED)
490 continue;
491
492 if (ch->flags & IEEE80211_CHAN_RADAR)
493 ch->flags |= IEEE80211_CHAN_NO_IBSS |
494 IEEE80211_CHAN_PASSIVE_SCAN;
495
496 }
497
498 return 0;
499}
500
Eliad Peller77ddaa12011-05-15 11:10:29 +0300501static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
502{
503 int ret = 0;
504
505 /* we should hold wl->mutex */
506 ret = wl1271_acx_ps_rx_streaming(wl, enable);
507 if (ret < 0)
508 goto out;
509
510 if (enable)
511 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
512 else
513 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
514out:
515 return ret;
516}
517
518/*
519 * this function is being called when the rx_streaming interval
520 * has beed changed or rx_streaming should be disabled
521 */
522int wl1271_recalc_rx_streaming(struct wl1271 *wl)
523{
524 int ret = 0;
525 int period = wl->conf.rx_streaming.interval;
526
527 /* don't reconfigure if rx_streaming is disabled */
528 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
529 goto out;
530
531 /* reconfigure/disable according to new streaming_period */
532 if (period &&
533 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
534 (wl->conf.rx_streaming.always ||
535 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
536 ret = wl1271_set_rx_streaming(wl, true);
537 else {
538 ret = wl1271_set_rx_streaming(wl, false);
539 /* don't cancel_work_sync since we might deadlock */
540 del_timer_sync(&wl->rx_streaming_timer);
541 }
542out:
543 return ret;
544}
545
546static void wl1271_rx_streaming_enable_work(struct work_struct *work)
547{
548 int ret;
549 struct wl1271 *wl =
550 container_of(work, struct wl1271, rx_streaming_enable_work);
551
552 mutex_lock(&wl->mutex);
553
554 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
555 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
556 (!wl->conf.rx_streaming.always &&
557 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
558 goto out;
559
560 if (!wl->conf.rx_streaming.interval)
561 goto out;
562
563 ret = wl1271_ps_elp_wakeup(wl);
564 if (ret < 0)
565 goto out;
566
567 ret = wl1271_set_rx_streaming(wl, true);
568 if (ret < 0)
569 goto out_sleep;
570
571 /* stop it after some time of inactivity */
572 mod_timer(&wl->rx_streaming_timer,
573 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
574
575out_sleep:
576 wl1271_ps_elp_sleep(wl);
577out:
578 mutex_unlock(&wl->mutex);
579}
580
581static void wl1271_rx_streaming_disable_work(struct work_struct *work)
582{
583 int ret;
584 struct wl1271 *wl =
585 container_of(work, struct wl1271, rx_streaming_disable_work);
586
587 mutex_lock(&wl->mutex);
588
589 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
590 goto out;
591
592 ret = wl1271_ps_elp_wakeup(wl);
593 if (ret < 0)
594 goto out;
595
596 ret = wl1271_set_rx_streaming(wl, false);
597 if (ret)
598 goto out_sleep;
599
600out_sleep:
601 wl1271_ps_elp_sleep(wl);
602out:
603 mutex_unlock(&wl->mutex);
604}
605
606static void wl1271_rx_streaming_timer(unsigned long data)
607{
608 struct wl1271 *wl = (struct wl1271 *)data;
609 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
610}
611
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300612static void wl1271_conf_init(struct wl1271 *wl)
613{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
615 /*
616 * This function applies the default configuration to the driver. This
617 * function is invoked upon driver load (spi probe.)
618 *
619 * The configuration is stored in a run-time structure in order to
620 * facilitate for run-time adjustment of any of the parameters. Making
621 * changes to the configuration structure will apply the new values on
622 * the next interface up (wl1271_op_start.)
623 */
624
625 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300626 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
Ido Yariv95dac04f2011-06-06 14:57:06 +0300628 /* Adjust settings according to optional module parameters */
629 if (fwlog_param) {
630 if (!strcmp(fwlog_param, "continuous")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 } else if (!strcmp(fwlog_param, "ondemand")) {
633 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
634 } else if (!strcmp(fwlog_param, "dbgpins")) {
635 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
636 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
637 } else if (!strcmp(fwlog_param, "disable")) {
638 wl->conf.fwlog.mem_blocks = 0;
639 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
640 } else {
641 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
642 }
643 }
644}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646static int wl1271_plt_init(struct wl1271 *wl)
647{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200648 struct conf_tx_ac_category *conf_ac;
649 struct conf_tx_tid *conf_tid;
650 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Shahar Levi49d750ca2011-03-06 16:32:09 +0200652 if (wl->chip.id == CHIP_ID_1283_PG20)
653 ret = wl128x_cmd_general_parms(wl);
654 else
655 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200656 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200657 return ret;
658
Shahar Levi49d750ca2011-03-06 16:32:09 +0200659 if (wl->chip.id == CHIP_ID_1283_PG20)
660 ret = wl128x_cmd_radio_parms(wl);
661 else
662 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200663 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200664 return ret;
665
Shahar Levi49d750ca2011-03-06 16:32:09 +0200666 if (wl->chip.id != CHIP_ID_1283_PG20) {
667 ret = wl1271_cmd_ext_radio_parms(wl);
668 if (ret < 0)
669 return ret;
670 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200671 if (ret < 0)
672 return ret;
673
Shahar Levi48a61472011-03-06 16:32:08 +0200674 /* Chip-specific initializations */
675 ret = wl1271_chip_specific_init(wl);
676 if (ret < 0)
677 return ret;
678
Eliad Peller92c77c72011-10-05 11:55:40 +0200679 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 /* PHY layer config */
688 ret = wl1271_init_phy_config(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 ret = wl1271_acx_dco_itrim_params(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200697 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Bluetooth WLAN coexistence */
702 ret = wl1271_init_pta(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
Shahar Leviff868432011-04-11 15:41:46 +0300706 /* FM WLAN coexistence */
707 ret = wl1271_acx_fm_coex(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Luciano Coelho12419cc2010-02-18 13:25:44 +0200711 /* Energy detection */
712 ret = wl1271_init_energy_detection(wl);
713 if (ret < 0)
714 goto out_free_memmap;
715
Eliad Peller7f0979882011-08-14 13:17:06 +0300716 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho12419cc2010-02-18 13:25:44 +0200720 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100721 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 if (ret < 0)
723 goto out_free_memmap;
724
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200725 /* Default TID/AC configuration */
726 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200727 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200728 conf_ac = &wl->conf.tx.ac_conf[i];
729 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
730 conf_ac->cw_max, conf_ac->aifsn,
731 conf_ac->tx_op_limit);
732 if (ret < 0)
733 goto out_free_memmap;
734
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid = &wl->conf.tx.tid_conf[i];
736 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
737 conf_tid->channel_type,
738 conf_tid->tsid,
739 conf_tid->ps_scheme,
740 conf_tid->ack_policy,
741 conf_tid->apsd_conf[0],
742 conf_tid->apsd_conf[1]);
743 if (ret < 0)
744 goto out_free_memmap;
745 }
746
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200748 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 goto out_free_memmap;
751
752 /* Configure for CAM power saving (ie. always active) */
753 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
754 if (ret < 0)
755 goto out_free_memmap;
756
757 /* configure PM */
758 ret = wl1271_acx_pm_config(wl);
759 if (ret < 0)
760 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763
764 out_free_memmap:
765 kfree(wl->target_mem_map);
766 wl->target_mem_map = NULL;
767
768 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769}
770
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300771static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
775 /* only regulate station links */
776 if (hlid < WL1271_AP_STA_HLID_START)
777 return;
778
779 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300780 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781
782 /*
783 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300784 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300786 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787 wl1271_ps_link_end(wl, hlid);
788
Arik Nemtsovda032092011-08-25 12:43:15 +0300789 /*
790 * Start high-level PS if the STA is asleep with enough blocks in FW.
791 * Make an exception if this is the only connected station. In this
792 * case FW-memory congestion is not a problem.
793 */
794 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200795 wl1271_ps_link_start(wl, hlid, true);
796}
797
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300798bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
799{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300800 int id;
801
802 /* global/broadcast "stations" are always active */
803 if (hlid < WL1271_AP_STA_HLID_START)
804 return true;
805
806 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300807 return test_bit(id, wl->ap_hlid_map);
808}
809
810static void wl12xx_irq_update_links_status(struct wl1271 *wl,
811 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812{
813 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300814 u8 hlid, cnt;
815
816 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
818 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
819 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
820 wl1271_debug(DEBUG_PSM,
821 "link ps prev 0x%x cur 0x%x changed 0x%x",
822 wl->ap_fw_ps_map, cur_fw_ps_map,
823 wl->ap_fw_ps_map ^ cur_fw_ps_map);
824
825 wl->ap_fw_ps_map = cur_fw_ps_map;
826 }
827
828 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300829 if (!wl1271_is_active_sta(wl, hlid))
830 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200831
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300832 cnt = status->tx_lnk_free_pkts[hlid] -
833 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200834
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300835 wl->links[hlid].prev_freed_pkts =
836 status->tx_lnk_free_pkts[hlid];
837 wl->links[hlid].allocated_pkts -= cnt;
838
839 wl12xx_irq_ps_regulate_link(wl, hlid,
840 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200841 }
842}
843
Eliad Peller4d56ad92011-08-14 13:17:05 +0300844static void wl12xx_fw_status(struct wl1271 *wl,
845 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200847 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200848 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300849 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300850 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
855 "drv_rx_counter = %d, tx_results_counter = %d)",
856 status->intr,
857 status->fw_rx_counter,
858 status->drv_rx_counter,
859 status->tx_results_counter);
860
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300861 for (i = 0; i < NUM_TX_QUEUES; i++) {
862 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300863 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300864 (status->tx_released_pkts[i] -
865 wl->tx_pkts_freed[i]) & 0xff;
866
867 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
868 }
869
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300870 /* prevent wrap-around in total blocks counter */
871 if (likely(wl->tx_blocks_freed <=
872 le32_to_cpu(status->total_released_blks)))
873 freed_blocks = le32_to_cpu(status->total_released_blks) -
874 wl->tx_blocks_freed;
875 else
876 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
877 le32_to_cpu(status->total_released_blks);
878
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200880
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300881 wl->tx_allocated_blocks -= freed_blocks;
882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200884
Eliad Peller4d56ad92011-08-14 13:17:05 +0300885 /*
886 * The FW might change the total number of TX memblocks before
887 * we get a notification about blocks being released. Thus, the
888 * available blocks calculation might yield a temporary result
889 * which is lower than the actual available blocks. Keeping in
890 * mind that only blocks that were allocated can be moved from
891 * TX to RX, tx_blocks_available should never decrease here.
892 */
893 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
894 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
Ido Yariva5225502010-10-12 14:49:10 +0200896 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200897 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200898 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
Eliad Peller4d56ad92011-08-14 13:17:05 +0300900 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300901 if (wl->bss_type == BSS_TYPE_AP_BSS)
902 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300903
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200905 getnstimeofday(&ts);
906 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
907 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908}
909
Ido Yariva6208652011-03-01 15:14:41 +0200910static void wl1271_flush_deferred_work(struct wl1271 *wl)
911{
912 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Ido Yariva6208652011-03-01 15:14:41 +0200914 /* Pass all received frames to the network stack */
915 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
916 ieee80211_rx_ni(wl->hw, skb);
917
918 /* Return sent skbs to the network stack */
919 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300920 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200921}
922
923static void wl1271_netstack_work(struct work_struct *work)
924{
925 struct wl1271 *wl =
926 container_of(work, struct wl1271, netstack_work);
927
928 do {
929 wl1271_flush_deferred_work(wl);
930 } while (skb_queue_len(&wl->deferred_rx_queue));
931}
932
933#define WL1271_IRQ_MAX_LOOPS 256
934
935irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300938 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200939 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200940 struct wl1271 *wl = (struct wl1271 *)cookie;
941 bool done = false;
942 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200943 unsigned long flags;
944
945 /* TX might be handled here, avoid redundant work */
946 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
947 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948
Ido Yariv341b7cd2011-03-31 10:07:01 +0200949 /*
950 * In case edge triggered interrupt must be used, we cannot iterate
951 * more than once without introducing race conditions with the hardirq.
952 */
953 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
954 loopcount = 1;
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 mutex_lock(&wl->mutex);
957
958 wl1271_debug(DEBUG_IRQ, "IRQ work");
959
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 goto out;
962
Ido Yariva6208652011-03-01 15:14:41 +0200963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 if (ret < 0)
965 goto out;
966
Ido Yariva6208652011-03-01 15:14:41 +0200967 while (!done && loopcount--) {
968 /*
969 * In order to avoid a race with the hardirq, clear the flag
970 * before acknowledging the chip. Since the mutex is held,
971 * wl1271_ps_elp_wakeup cannot be called concurrently.
972 */
973 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
974 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975
Eliad Peller4d56ad92011-08-14 13:17:05 +0300976 wl12xx_fw_status(wl, wl->fw_status);
977 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200978 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200979 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200980 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981 continue;
982 }
983
Eliad Pellerccc83b02010-10-27 14:09:57 +0200984 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
985 wl1271_error("watchdog interrupt received! "
986 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300987 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200988
989 /* restarting the chip. ignore any other interrupt. */
990 goto out;
991 }
992
Ido Yariva6208652011-03-01 15:14:41 +0200993 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200994 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
995
Eliad Peller4d56ad92011-08-14 13:17:05 +0300996 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200997
Ido Yariva5225502010-10-12 14:49:10 +0200998 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200999 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001000 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001001 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001003 /*
1004 * In order to avoid starvation of the TX path,
1005 * call the work function directly.
1006 */
1007 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001008 } else {
1009 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001010 }
1011
Ido Yariv8aad2462011-03-01 15:14:38 +02001012 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001013 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001014 (wl->tx_results_count & 0xff))
1015 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001016
1017 /* Make sure the deferred queues don't get too long */
1018 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1019 skb_queue_len(&wl->deferred_rx_queue);
1020 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1021 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001022 }
1023
1024 if (intr & WL1271_ACX_INTR_EVENT_A) {
1025 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1026 wl1271_event_handle(wl, 0);
1027 }
1028
1029 if (intr & WL1271_ACX_INTR_EVENT_B) {
1030 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1031 wl1271_event_handle(wl, 1);
1032 }
1033
1034 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1035 wl1271_debug(DEBUG_IRQ,
1036 "WL1271_ACX_INTR_INIT_COMPLETE");
1037
1038 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1039 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 wl1271_ps_elp_sleep(wl);
1043
1044out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001045 spin_lock_irqsave(&wl->wl_lock, flags);
1046 /* In case TX was not handled here, queue TX work */
1047 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1048 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001049 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001050 ieee80211_queue_work(wl->hw, &wl->tx_work);
1051 spin_unlock_irqrestore(&wl->wl_lock, flags);
1052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001054
1055 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056}
Ido Yariva6208652011-03-01 15:14:41 +02001057EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059static int wl1271_fetch_firmware(struct wl1271 *wl)
1060{
1061 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 int ret;
1064
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001065 if (wl->chip.id == CHIP_ID_1283_PG20)
1066 fw_name = WL128X_FW_NAME;
1067 else
1068 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069
1070 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1071
1072 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
1074 if (ret < 0) {
1075 wl1271_error("could not get firmware: %d", ret);
1076 return ret;
1077 }
1078
1079 if (fw->size % 4) {
1080 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1081 fw->size);
1082 ret = -EILSEQ;
1083 goto out;
1084 }
1085
Arik Nemtsov166d5042010-10-16 21:44:57 +02001086 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001088 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089
1090 if (!wl->fw) {
1091 wl1271_error("could not allocate memory for the firmware");
1092 ret = -ENOMEM;
1093 goto out;
1094 }
1095
1096 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 ret = 0;
1098
1099out:
1100 release_firmware(fw);
1101
1102 return ret;
1103}
1104
1105static int wl1271_fetch_nvs(struct wl1271 *wl)
1106{
1107 const struct firmware *fw;
1108 int ret;
1109
Shahar Levi5aa42342011-03-06 16:32:07 +02001110 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 if (ret < 0) {
1113 wl1271_error("could not get nvs file: %d", ret);
1114 return ret;
1115 }
1116
Shahar Levibc765bf2011-03-06 16:32:10 +02001117 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001118
1119 if (!wl->nvs) {
1120 wl1271_error("could not allocate memory for the nvs file");
1121 ret = -ENOMEM;
1122 goto out;
1123 }
1124
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001125 wl->nvs_len = fw->size;
1126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127out:
1128 release_firmware(fw);
1129
1130 return ret;
1131}
1132
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001133void wl12xx_queue_recovery_work(struct wl1271 *wl)
1134{
1135 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1136 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1137}
1138
Ido Yariv95dac04f2011-06-06 14:57:06 +03001139size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1140{
1141 size_t len = 0;
1142
1143 /* The FW log is a length-value list, find where the log end */
1144 while (len < maxlen) {
1145 if (memblock[len] == 0)
1146 break;
1147 if (len + memblock[len] + 1 > maxlen)
1148 break;
1149 len += memblock[len] + 1;
1150 }
1151
1152 /* Make sure we have enough room */
1153 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1154
1155 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1156 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1157 wl->fwlog_size += len;
1158
1159 return len;
1160}
1161
1162static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1163{
1164 u32 addr;
1165 u32 first_addr;
1166 u8 *block;
1167
1168 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1169 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1170 (wl->conf.fwlog.mem_blocks == 0))
1171 return;
1172
1173 wl1271_info("Reading FW panic log");
1174
1175 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1176 if (!block)
1177 return;
1178
1179 /*
1180 * Make sure the chip is awake and the logger isn't active.
1181 * This might fail if the firmware hanged.
1182 */
1183 if (!wl1271_ps_elp_wakeup(wl))
1184 wl12xx_cmd_stop_fwlog(wl);
1185
1186 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 wl12xx_fw_status(wl, wl->fw_status);
1188 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001189 if (!first_addr)
1190 goto out;
1191
1192 /* Traverse the memory blocks linked list */
1193 addr = first_addr;
1194 do {
1195 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1196 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1197 false);
1198
1199 /*
1200 * Memory blocks are linked to one another. The first 4 bytes
1201 * of each memory block hold the hardware address of the next
1202 * one. The last memory block points to the first one.
1203 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001204 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001205 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1206 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1207 break;
1208 } while (addr && (addr != first_addr));
1209
1210 wake_up_interruptible(&wl->fwlog_waitq);
1211
1212out:
1213 kfree(block);
1214}
1215
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216static void wl1271_recovery_work(struct work_struct *work)
1217{
1218 struct wl1271 *wl =
1219 container_of(work, struct wl1271, recovery_work);
1220
1221 mutex_lock(&wl->mutex);
1222
1223 if (wl->state != WL1271_STATE_ON)
1224 goto out;
1225
Ido Yarivbaacb9ae2011-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 */
1241 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1242 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1243 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1244
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001245 /* Prevent spurious TX during FW restart */
1246 ieee80211_stop_queues(wl->hw);
1247
Luciano Coelho33c2c062011-05-10 14:46:02 +03001248 if (wl->sched_scanning) {
1249 ieee80211_sched_scan_stopped(wl->hw);
1250 wl->sched_scanning = false;
1251 }
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001254 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001255
1256 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1257
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001258 ieee80211_restart_hw(wl->hw);
1259
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001260 /*
1261 * Its safe to enable TX now - the queues are stopped after a request
1262 * to restart the HW.
1263 */
1264 ieee80211_wake_queues(wl->hw);
1265
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001266out:
1267 mutex_unlock(&wl->mutex);
1268}
1269
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270static void wl1271_fw_wakeup(struct wl1271 *wl)
1271{
1272 u32 elp_reg;
1273
1274 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001275 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276}
1277
1278static int wl1271_setup(struct wl1271 *wl)
1279{
1280 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1281 if (!wl->fw_status)
1282 return -ENOMEM;
1283
1284 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1285 if (!wl->tx_res_if) {
1286 kfree(wl->fw_status);
1287 return -ENOMEM;
1288 }
1289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 return 0;
1291}
1292
1293static int wl1271_chip_wakeup(struct wl1271 *wl)
1294{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001295 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 int ret = 0;
1297
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001298 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001299 ret = wl1271_power_on(wl);
1300 if (ret < 0)
1301 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001303 wl1271_io_reset(wl);
1304 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305
1306 /* We don't need a real memory partition here, because we only want
1307 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001308 memset(&partition, 0, sizeof(partition));
1309 partition.reg.start = REGISTERS_BASE;
1310 partition.reg.size = REGISTERS_DOWN_SIZE;
1311 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312
1313 /* ELP module wake up */
1314 wl1271_fw_wakeup(wl);
1315
1316 /* whal_FwCtrl_BootSm() */
1317
1318 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001319 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
1321 /* 1. check if chip id is valid */
1322
1323 switch (wl->chip.id) {
1324 case CHIP_ID_1271_PG10:
1325 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1326 wl->chip.id);
1327
1328 ret = wl1271_setup(wl);
1329 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 break;
1332 case CHIP_ID_1271_PG20:
1333 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1334 wl->chip.id);
1335
1336 ret = wl1271_setup(wl);
1337 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001338 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001340 case CHIP_ID_1283_PG20:
1341 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1342 wl->chip.id);
1343
1344 ret = wl1271_setup(wl);
1345 if (ret < 0)
1346 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001347
Ido Yariv0da13da2011-03-31 10:06:58 +02001348 if (wl1271_set_block_size(wl))
1349 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001350 break;
1351 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001355 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 }
1357
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001358 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 ret = wl1271_fetch_firmware(wl);
1360 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001361 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 }
1363
1364 /* No NVS from netlink, try to get it from the filesystem */
1365 if (wl->nvs == NULL) {
1366 ret = wl1271_fetch_nvs(wl);
1367 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 }
1370
1371out:
1372 return ret;
1373}
1374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375int wl1271_plt_start(struct wl1271 *wl)
1376{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001377 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001378 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379 int ret;
1380
1381 mutex_lock(&wl->mutex);
1382
1383 wl1271_notice("power up");
1384
1385 if (wl->state != WL1271_STATE_OFF) {
1386 wl1271_error("cannot go into PLT state because not "
1387 "in off state: %d", wl->state);
1388 ret = -EBUSY;
1389 goto out;
1390 }
1391
Arik Nemtsov166d5042010-10-16 21:44:57 +02001392 wl->bss_type = BSS_TYPE_STA_BSS;
1393
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 while (retries) {
1395 retries--;
1396 ret = wl1271_chip_wakeup(wl);
1397 if (ret < 0)
1398 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001400 ret = wl1271_boot(wl);
1401 if (ret < 0)
1402 goto power_off;
1403
1404 ret = wl1271_plt_init(wl);
1405 if (ret < 0)
1406 goto irq_disable;
1407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 wl->state = WL1271_STATE_PLT;
1409 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001410 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001411
Gery Kahn6f07b722011-07-18 14:21:49 +03001412 /* update hw/fw version info in wiphy struct */
1413 wiphy->hw_version = wl->chip.id;
1414 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1415 sizeof(wiphy->fw_version));
1416
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 goto out;
1418
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001419irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001420 mutex_unlock(&wl->mutex);
1421 /* Unlocking the mutex in the middle of handling is
1422 inherently unsafe. In this case we deem it safe to do,
1423 because we need to let any possibly pending IRQ out of
1424 the system (and while we are WL1271_STATE_OFF the IRQ
1425 work function will not do anything.) Also, any other
1426 possible concurrent operations will fail due to the
1427 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001428 wl1271_disable_interrupts(wl);
1429 wl1271_flush_deferred_work(wl);
1430 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001431 mutex_lock(&wl->mutex);
1432power_off:
1433 wl1271_power_off(wl);
1434 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001436 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1437 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438out:
1439 mutex_unlock(&wl->mutex);
1440
1441 return ret;
1442}
1443
Luciano Coelho4623ec72011-03-21 19:26:41 +02001444static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445{
1446 int ret = 0;
1447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448 wl1271_notice("power down");
1449
1450 if (wl->state != WL1271_STATE_PLT) {
1451 wl1271_error("cannot power down because not in PLT "
1452 "state: %d", wl->state);
1453 ret = -EBUSY;
1454 goto out;
1455 }
1456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 wl1271_power_off(wl);
1458
1459 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001460 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001463 wl1271_disable_interrupts(wl);
1464 wl1271_flush_deferred_work(wl);
1465 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001466 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001467 mutex_lock(&wl->mutex);
1468out:
1469 return ret;
1470}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001471
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001472int wl1271_plt_stop(struct wl1271 *wl)
1473{
1474 int ret;
1475
1476 mutex_lock(&wl->mutex);
1477 ret = __wl1271_plt_stop(wl);
1478 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 return ret;
1480}
1481
Johannes Berg7bb45682011-02-24 14:42:06 +01001482static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483{
1484 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001485 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001486 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001487 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 mapping = skb_get_queue_mapping(skb);
1490 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001491
1492 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001493 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001496
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001497 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001498 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001499 if (!wl1271_is_active_sta(wl, hlid)) {
1500 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1501 hlid, q);
1502 dev_kfree_skb(skb);
1503 goto out;
1504 }
1505
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001506 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1507 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1508 } else {
1509 skb_queue_tail(&wl->tx_queue[q], skb);
1510 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001512 wl->tx_queue_count[q]++;
1513
1514 /*
1515 * The workqueue is slow to process the tx_queue and we need stop
1516 * the queue here, otherwise the queue will get too long.
1517 */
1518 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1519 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1520 ieee80211_stop_queue(wl->hw, mapping);
1521 set_bit(q, &wl->stopped_queues_map);
1522 }
1523
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524 /*
1525 * The chip specific setup must run before the first TX packet -
1526 * before that, the tx_work will not be initialized!
1527 */
1528
Ido Yarivb07d4032011-03-01 15:14:43 +02001529 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1530 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001531 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001532
Arik Nemtsov04216da2011-08-14 13:17:38 +03001533out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001534 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535}
1536
Shahar Leviae47c452011-03-06 16:32:14 +02001537int wl1271_tx_dummy_packet(struct wl1271 *wl)
1538{
Ido Yariv990f5de2011-03-31 10:06:59 +02001539 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001540 int q;
1541
1542 /* no need to queue a new dummy packet if one is already pending */
1543 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1544 return 0;
1545
1546 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001547
Ido Yariv990f5de2011-03-31 10:06:59 +02001548 spin_lock_irqsave(&wl->wl_lock, flags);
1549 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001550 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 spin_unlock_irqrestore(&wl->wl_lock, flags);
1552
1553 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1554 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1555 wl1271_tx_work_locked(wl);
1556
1557 /*
1558 * If the FW TX is busy, TX work will be scheduled by the threaded
1559 * interrupt handler function
1560 */
1561 return 0;
1562}
1563
1564/*
1565 * The size of the dummy packet should be at least 1400 bytes. However, in
1566 * order to minimize the number of bus transactions, aligning it to 512 bytes
1567 * boundaries could be beneficial, performance wise
1568 */
1569#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1570
Luciano Coelhocf27d862011-04-01 21:08:23 +03001571static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001572{
1573 struct sk_buff *skb;
1574 struct ieee80211_hdr_3addr *hdr;
1575 unsigned int dummy_packet_size;
1576
1577 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1578 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1579
1580 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001581 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001582 wl1271_warning("Failed to allocate a dummy packet skb");
1583 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001584 }
1585
1586 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1587
1588 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1589 memset(hdr, 0, sizeof(*hdr));
1590 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001591 IEEE80211_STYPE_NULLFUNC |
1592 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001593
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001595
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001596 /* Dummy packets require the TID to be management */
1597 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001598
1599 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001600 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001601 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001602
Ido Yariv990f5de2011-03-31 10:06:59 +02001603 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001604}
1605
Ido Yariv990f5de2011-03-31 10:06:59 +02001606
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001607static struct notifier_block wl1271_dev_notifier = {
1608 .notifier_call = wl1271_dev_notify,
1609};
1610
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001611#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001612static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001613{
Eliad Pellere85d1622011-06-27 13:06:43 +03001614 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001615
Eliad Peller94390642011-05-13 11:57:13 +03001616 mutex_lock(&wl->mutex);
1617
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1619 goto out_unlock;
1620
Eliad Peller94390642011-05-13 11:57:13 +03001621 ret = wl1271_ps_elp_wakeup(wl);
1622 if (ret < 0)
1623 goto out_unlock;
1624
1625 /* enter psm if needed*/
1626 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1627 DECLARE_COMPLETION_ONSTACK(compl);
1628
1629 wl->ps_compl = &compl;
1630 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1631 wl->basic_rate, true);
1632 if (ret < 0)
1633 goto out_sleep;
1634
1635 /* we must unlock here so we will be able to get events */
1636 wl1271_ps_elp_sleep(wl);
1637 mutex_unlock(&wl->mutex);
1638
1639 ret = wait_for_completion_timeout(
1640 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1641 if (ret <= 0) {
1642 wl1271_warning("couldn't enter ps mode!");
1643 ret = -EBUSY;
1644 goto out;
1645 }
1646
1647 /* take mutex again, and wakeup */
1648 mutex_lock(&wl->mutex);
1649
1650 ret = wl1271_ps_elp_wakeup(wl);
1651 if (ret < 0)
1652 goto out_unlock;
1653 }
1654out_sleep:
1655 wl1271_ps_elp_sleep(wl);
1656out_unlock:
1657 mutex_unlock(&wl->mutex);
1658out:
1659 return ret;
1660
1661}
1662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001664{
Eliad Pellere85d1622011-06-27 13:06:43 +03001665 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001666
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001667 mutex_lock(&wl->mutex);
1668
Eliad Pellere85d1622011-06-27 13:06:43 +03001669 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1670 goto out_unlock;
1671
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001672 ret = wl1271_ps_elp_wakeup(wl);
1673 if (ret < 0)
1674 goto out_unlock;
1675
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001676 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001677
1678 wl1271_ps_elp_sleep(wl);
1679out_unlock:
1680 mutex_unlock(&wl->mutex);
1681 return ret;
1682
1683}
1684
1685static int wl1271_configure_suspend(struct wl1271 *wl)
1686{
1687 if (wl->bss_type == BSS_TYPE_STA_BSS)
1688 return wl1271_configure_suspend_sta(wl);
1689 if (wl->bss_type == BSS_TYPE_AP_BSS)
1690 return wl1271_configure_suspend_ap(wl);
1691 return 0;
1692}
1693
1694static void wl1271_configure_resume(struct wl1271 *wl)
1695{
1696 int ret;
1697 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1698 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1699
1700 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001701 return;
1702
1703 mutex_lock(&wl->mutex);
1704 ret = wl1271_ps_elp_wakeup(wl);
1705 if (ret < 0)
1706 goto out;
1707
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001708 if (is_sta) {
1709 /* exit psm if it wasn't configured */
1710 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1711 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1712 wl->basic_rate, true);
1713 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001714 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001715 }
Eliad Peller94390642011-05-13 11:57:13 +03001716
1717 wl1271_ps_elp_sleep(wl);
1718out:
1719 mutex_unlock(&wl->mutex);
1720}
1721
Eliad Peller402e48612011-05-13 11:57:09 +03001722static int wl1271_op_suspend(struct ieee80211_hw *hw,
1723 struct cfg80211_wowlan *wow)
1724{
1725 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 int ret;
1727
Eliad Peller402e48612011-05-13 11:57:09 +03001728 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 wl->wow_enabled = true;
1732 ret = wl1271_configure_suspend(wl);
1733 if (ret < 0) {
1734 wl1271_warning("couldn't prepare device to suspend");
1735 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001736 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 /* flush any remaining work */
1738 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001739
1740 /*
1741 * disable and re-enable interrupts in order to flush
1742 * the threaded_irq
1743 */
1744 wl1271_disable_interrupts(wl);
1745
1746 /*
1747 * set suspended flag to avoid triggering a new threaded_irq
1748 * work. no need for spinlock as interrupts are disabled.
1749 */
1750 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1751
1752 wl1271_enable_interrupts(wl);
1753 flush_work(&wl->tx_work);
1754 flush_delayed_work(&wl->pspoll_work);
1755 flush_delayed_work(&wl->elp_work);
1756
Eliad Peller402e48612011-05-13 11:57:09 +03001757 return 0;
1758}
1759
1760static int wl1271_op_resume(struct ieee80211_hw *hw)
1761{
1762 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001763 unsigned long flags;
1764 bool run_irq_work = false;
1765
Eliad Peller402e48612011-05-13 11:57:09 +03001766 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1767 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001768 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001769
1770 /*
1771 * re-enable irq_work enqueuing, and call irq_work directly if
1772 * there is a pending work.
1773 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001774 spin_lock_irqsave(&wl->wl_lock, flags);
1775 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1776 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1777 run_irq_work = true;
1778 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001779
Eliad Peller4a859df2011-06-06 12:21:52 +03001780 if (run_irq_work) {
1781 wl1271_debug(DEBUG_MAC80211,
1782 "run postponed irq_work directly");
1783 wl1271_irq(0, wl);
1784 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001785 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001786 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001787 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001788
Eliad Peller402e48612011-05-13 11:57:09 +03001789 return 0;
1790}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001791#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793static int wl1271_op_start(struct ieee80211_hw *hw)
1794{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001795 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1796
1797 /*
1798 * We have to delay the booting of the hardware because
1799 * we need to know the local MAC address before downloading and
1800 * initializing the firmware. The MAC address cannot be changed
1801 * after boot, and without the proper MAC address, the firmware
1802 * will not function properly.
1803 *
1804 * The MAC address is first known when the corresponding interface
1805 * is added. That is where we will initialize the hardware.
1806 */
1807
1808 return 0;
1809}
1810
1811static void wl1271_op_stop(struct ieee80211_hw *hw)
1812{
1813 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1814}
1815
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001816static u8 wl12xx_get_role_type(struct wl1271 *wl)
1817{
1818 switch (wl->bss_type) {
1819 case BSS_TYPE_AP_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001820 if (wl->p2p)
1821 return WL1271_ROLE_P2P_GO;
1822 else
1823 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001824
1825 case BSS_TYPE_STA_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001826 if (wl->p2p)
1827 return WL1271_ROLE_P2P_CL;
1828 else
1829 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001830
Eliad Peller227e81e2011-08-14 13:17:26 +03001831 case BSS_TYPE_IBSS:
1832 return WL1271_ROLE_IBSS;
1833
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001834 default:
1835 wl1271_error("invalid bss_type: %d", wl->bss_type);
1836 }
1837 return WL12XX_INVALID_ROLE_TYPE;
1838}
1839
Eliad Peller87fbcb02011-10-05 11:55:41 +02001840static void wl12xx_init_vif_data(struct wl12xx_vif *wlvif)
1841{
1842 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001843 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001844}
1845
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001846static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1847 struct ieee80211_vif *vif)
1848{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001850 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001851 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001853 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001854 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001856 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03001857 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001858
1859 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001860 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001861 wl1271_debug(DEBUG_MAC80211,
1862 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001863 ret = -EBUSY;
1864 goto out;
1865 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02001866 wl12xx_init_vif_data(wl12xx_vif_to_data(vif));
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001867
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001868 /*
1869 * in some very corner case HW recovery scenarios its possible to
1870 * get here before __wl1271_op_remove_interface is complete, so
1871 * opt out if that is the case.
1872 */
1873 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1874 ret = -EBUSY;
1875 goto out;
1876 }
1877
Eliad Peller045c7452011-08-28 15:23:01 +03001878 switch (ieee80211_vif_type_p2p(vif)) {
1879 case NL80211_IFTYPE_P2P_CLIENT:
1880 wl->p2p = 1;
1881 /* fall-through */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001882 case NL80211_IFTYPE_STATION:
1883 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001884 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001885 break;
1886 case NL80211_IFTYPE_ADHOC:
1887 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001888 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001889 break;
Eliad Peller045c7452011-08-28 15:23:01 +03001890 case NL80211_IFTYPE_P2P_GO:
1891 wl->p2p = 1;
1892 /* fall-through */
Arik Nemtsov038d9252010-10-16 21:53:24 +02001893 case NL80211_IFTYPE_AP:
1894 wl->bss_type = BSS_TYPE_AP_BSS;
1895 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001896 default:
1897 ret = -EOPNOTSUPP;
1898 goto out;
1899 }
1900
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001901 role_type = wl12xx_get_role_type(wl);
1902 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1903 ret = -EINVAL;
1904 goto out;
1905 }
Eliad Peller784f6942011-10-05 11:55:39 +02001906 /*
1907 * we still need this in order to configure the fw
1908 * while uploading the nvs
1909 */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001910 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001911
1912 if (wl->state != WL1271_STATE_OFF) {
1913 wl1271_error("cannot start because not in off state: %d",
1914 wl->state);
1915 ret = -EBUSY;
1916 goto out;
1917 }
1918
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001919 while (retries) {
1920 retries--;
1921 ret = wl1271_chip_wakeup(wl);
1922 if (ret < 0)
1923 goto power_off;
1924
1925 ret = wl1271_boot(wl);
1926 if (ret < 0)
1927 goto power_off;
1928
Eliad Peller92c77c72011-10-05 11:55:40 +02001929 ret = wl1271_hw_init(wl);
1930 if (ret < 0)
1931 goto irq_disable;
1932
Eliad Peller227e81e2011-08-14 13:17:26 +03001933 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1934 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001935 /*
1936 * The device role is a special role used for
1937 * rx and tx frames prior to association (as
1938 * the STA role can get packets only from
1939 * its associated bssid)
1940 */
Eliad Peller784f6942011-10-05 11:55:39 +02001941 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller04e80792011-08-14 13:17:09 +03001942 WL1271_ROLE_DEVICE,
1943 &wl->dev_role_id);
1944 if (ret < 0)
1945 goto irq_disable;
1946 }
1947
Eliad Peller784f6942011-10-05 11:55:39 +02001948 ret = wl12xx_cmd_role_enable(wl, vif->addr,
1949 role_type, &wl->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001950 if (ret < 0)
1951 goto irq_disable;
1952
Eliad Peller92c77c72011-10-05 11:55:40 +02001953 ret = wl1271_init_vif_specific(wl, vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001954 if (ret < 0)
1955 goto irq_disable;
1956
Eliad Peller71125ab2010-10-28 21:46:43 +02001957 booted = true;
1958 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001960irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001961 mutex_unlock(&wl->mutex);
1962 /* Unlocking the mutex in the middle of handling is
1963 inherently unsafe. In this case we deem it safe to do,
1964 because we need to let any possibly pending IRQ out of
1965 the system (and while we are WL1271_STATE_OFF the IRQ
1966 work function will not do anything.) Also, any other
1967 possible concurrent operations will fail due to the
1968 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001969 wl1271_disable_interrupts(wl);
1970 wl1271_flush_deferred_work(wl);
1971 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001972 mutex_lock(&wl->mutex);
1973power_off:
1974 wl1271_power_off(wl);
1975 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976
Eliad Peller71125ab2010-10-28 21:46:43 +02001977 if (!booted) {
1978 wl1271_error("firmware boot failed despite %d retries",
1979 WL1271_BOOT_RETRIES);
1980 goto out;
1981 }
1982
1983 wl->vif = vif;
1984 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001985 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001986 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001987
1988 /* update hw/fw version info in wiphy struct */
1989 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001990 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001991 sizeof(wiphy->fw_version));
1992
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001993 /*
1994 * Now we know if 11a is supported (info from the NVS), so disable
1995 * 11a channels if not supported
1996 */
1997 if (!wl->enable_11a)
1998 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1999
2000 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2001 wl->enable_11a ? "" : "not ");
2002
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002003out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 mutex_unlock(&wl->mutex);
2005
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002006 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002007 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002008 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002009 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002010
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011 return ret;
2012}
2013
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002014static void __wl1271_op_remove_interface(struct wl1271 *wl,
2015 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002017 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002019 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002021 /* because of hardware recovery, we may get here twice */
2022 if (wl->state != WL1271_STATE_ON)
2023 return;
2024
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002025 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002027 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002028 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002029 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002030
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002031 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03002032 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002033 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002034
Luciano Coelho08688d62010-07-08 17:50:07 +03002035 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002036 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002037 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002038 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002039 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002040 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 }
2042
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002043 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2044 /* disable active roles */
2045 ret = wl1271_ps_elp_wakeup(wl);
2046 if (ret < 0)
2047 goto deinit;
2048
Eliad Peller04e80792011-08-14 13:17:09 +03002049 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2050 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2051 if (ret < 0)
2052 goto deinit;
2053 }
2054
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002055 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2056 if (ret < 0)
2057 goto deinit;
2058
2059 wl1271_ps_elp_sleep(wl);
2060 }
2061deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002062 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002063 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002064 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002065 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2066 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002067
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002068 /*
2069 * this must be before the cancel_work calls below, so that the work
2070 * functions don't perform further work.
2071 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072 wl->state = WL1271_STATE_OFF;
2073
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002074 mutex_unlock(&wl->mutex);
2075
Ido Yariva6208652011-03-01 15:14:41 +02002076 wl1271_disable_interrupts(wl);
2077 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002078 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002079 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002081 del_timer_sync(&wl->rx_streaming_timer);
2082 cancel_work_sync(&wl->rx_streaming_enable_work);
2083 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002084 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002085 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086
2087 mutex_lock(&wl->mutex);
2088
2089 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002090 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091 wl1271_power_off(wl);
2092
2093 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002094 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002096 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002097 wl->set_bss_type = MAX_BSS_TYPE;
Eliad Peller045c7452011-08-28 15:23:01 +03002098 wl->p2p = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002099 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
2101 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002102 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2104 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002105 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002106 wl->tx_results_count = 0;
2107 wl->tx_packets_count = 0;
2108 wl->time_offset = 0;
2109 wl->session_counter = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002110 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2111 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002112 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002113 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002114 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002115 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002116 wl->ap_fw_ps_map = 0;
2117 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002118 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002119 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002120 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002121 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2122 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002123 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002124 wl->active_sta_count = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002125
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002126 /* The system link is always allocated */
2127 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2128
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002129 /*
2130 * this is performed after the cancel_work calls and the associated
2131 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2132 * get executed before all these vars have been reset.
2133 */
2134 wl->flags = 0;
2135
Eliad Peller4d56ad92011-08-14 13:17:05 +03002136 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137
Arik Nemtsov742246f2011-08-14 13:17:33 +03002138 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002139 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002140 wl->tx_allocated_pkts[i] = 0;
2141 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002144
2145 kfree(wl->fw_status);
2146 wl->fw_status = NULL;
2147 kfree(wl->tx_res_if);
2148 wl->tx_res_if = NULL;
2149 kfree(wl->target_mem_map);
2150 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002151}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002152
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002153static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2154 struct ieee80211_vif *vif)
2155{
2156 struct wl1271 *wl = hw->priv;
2157
2158 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002159 /*
2160 * wl->vif can be null here if someone shuts down the interface
2161 * just when hardware recovery has been started.
2162 */
2163 if (wl->vif) {
2164 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002165 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002166 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002167
Juuso Oikarinen67353292010-11-18 15:19:02 +02002168 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002169 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170}
2171
Eliad Peller87fbcb02011-10-05 11:55:41 +02002172static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2173 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002174{
2175 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002176 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002177
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002178 /*
2179 * One of the side effects of the JOIN command is that is clears
2180 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2181 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002182 * Currently the only valid scenario for JOIN during association
2183 * is on roaming, in which case we will also be given new keys.
2184 * Keep the below message for now, unless it starts bothering
2185 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002186 */
2187 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2188 wl1271_info("JOIN while associated.");
2189
2190 if (set_assoc)
2191 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2192
Eliad Peller227e81e2011-08-14 13:17:26 +03002193 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002194 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002195 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002196 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002197 if (ret < 0)
2198 goto out;
2199
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002200 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2201 goto out;
2202
2203 /*
2204 * The join command disable the keep-alive mode, shut down its process,
2205 * and also clear the template config, so we need to reset it all after
2206 * the join. The acx_aid starts the keep-alive process, and the order
2207 * of the commands below is relevant.
2208 */
2209 ret = wl1271_acx_keep_alive_mode(wl, true);
2210 if (ret < 0)
2211 goto out;
2212
2213 ret = wl1271_acx_aid(wl, wl->aid);
2214 if (ret < 0)
2215 goto out;
2216
2217 ret = wl1271_cmd_build_klv_null_data(wl);
2218 if (ret < 0)
2219 goto out;
2220
2221 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2222 ACX_KEEP_ALIVE_TPL_VALID);
2223 if (ret < 0)
2224 goto out;
2225
2226out:
2227 return ret;
2228}
2229
2230static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002231{
2232 int ret;
2233
Shahar Levi6d158ff2011-09-08 13:01:33 +03002234 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2235 wl12xx_cmd_stop_channel_switch(wl);
2236 ieee80211_chswitch_done(wl->vif, false);
2237 }
2238
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002239 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002240 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002241 if (ret < 0)
2242 goto out;
2243
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002244 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002245
Oz Krakowskib992c682011-06-26 10:36:02 +03002246 /* reset TX security counters on a clean disconnect */
2247 wl->tx_security_last_seq_lsb = 0;
2248 wl->tx_security_seq = 0;
2249
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002250out:
2251 return ret;
2252}
2253
Eliad Peller87fbcb02011-10-05 11:55:41 +02002254static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002255{
Eliad Peller87fbcb02011-10-05 11:55:41 +02002256 wlvif->basic_rate_set = wl->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002257 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002258}
2259
Eliad Peller251c1772011-08-14 13:17:17 +03002260static bool wl12xx_is_roc(struct wl1271 *wl)
2261{
2262 u8 role_id;
2263
2264 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2265 if (role_id >= WL12XX_MAX_ROLES)
2266 return false;
2267
2268 return true;
2269}
2270
Eliad Peller87fbcb02011-10-05 11:55:41 +02002271static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2272 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002273{
2274 int ret;
2275
2276 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002277 /* no need to croc if we weren't busy (e.g. during boot) */
2278 if (wl12xx_is_roc(wl)) {
2279 ret = wl12xx_croc(wl, wl->dev_role_id);
2280 if (ret < 0)
2281 goto out;
2282
2283 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002284 if (ret < 0)
2285 goto out;
2286 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002287 wlvif->rate_set =
2288 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2289 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002290 if (ret < 0)
2291 goto out;
2292 ret = wl1271_acx_keep_alive_config(
2293 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2294 ACX_KEEP_ALIVE_TPL_INVALID);
2295 if (ret < 0)
2296 goto out;
2297 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2298 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002299 /* The current firmware only supports sched_scan in idle */
2300 if (wl->sched_scanning) {
2301 wl1271_scan_sched_scan_stop(wl);
2302 ieee80211_sched_scan_stopped(wl->hw);
2303 }
2304
Eliad Peller251c1772011-08-14 13:17:17 +03002305 ret = wl12xx_cmd_role_start_dev(wl);
2306 if (ret < 0)
2307 goto out;
2308
2309 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002310 if (ret < 0)
2311 goto out;
2312 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2313 }
2314
2315out:
2316 return ret;
2317}
2318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2320{
2321 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002322 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2323 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324 struct ieee80211_conf *conf = &hw->conf;
2325 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002326 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327
2328 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2329
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002330 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2331 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 channel,
2333 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002334 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002335 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2336 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002338 /*
2339 * mac80211 will go to idle nearly immediately after transmitting some
2340 * frames, such as the deauth. To make sure those frames reach the air,
2341 * wait here until the TX queue is fully flushed.
2342 */
2343 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2344 (conf->flags & IEEE80211_CONF_IDLE))
2345 wl1271_tx_flush(wl);
2346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347 mutex_lock(&wl->mutex);
2348
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002349 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002350 /* we support configuring the channel and band while off */
2351 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2352 wl->band = conf->channel->band;
2353 wl->channel = channel;
2354 }
2355
Arik Nemtsov097f8822011-06-27 22:06:34 +03002356 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2357 wl->power_level = conf->power_level;
2358
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002359 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002360 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002361
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002362 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2363
Ido Yariva6208652011-03-01 15:14:41 +02002364 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 if (ret < 0)
2366 goto out;
2367
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002368 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002369 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2370 ((wl->band != conf->channel->band) ||
2371 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002372 /* send all pending packets */
2373 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002374 wl->band = conf->channel->band;
2375 wl->channel = channel;
2376
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002377 if (!is_ap) {
2378 /*
2379 * FIXME: the mac80211 should really provide a fixed
2380 * rate to use here. for now, just use the smallest
2381 * possible rate for the band as a fixed rate for
2382 * association frames and other control messages.
2383 */
2384 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002385 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002386
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002387 wl->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002388 wl1271_tx_min_rate_get(wl,
2389 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002390 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002391 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002392 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002393 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002394
Eliad Peller251c1772011-08-14 13:17:17 +03002395 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2396 if (wl12xx_is_roc(wl)) {
2397 /* roaming */
2398 ret = wl12xx_croc(wl, wl->dev_role_id);
2399 if (ret < 0)
2400 goto out_sleep;
2401 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002402 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002403 if (ret < 0)
2404 wl1271_warning("cmd join on channel "
2405 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002406 } else {
2407 /*
2408 * change the ROC channel. do it only if we are
2409 * not idle. otherwise, CROC will be called
2410 * anyway.
2411 */
2412 if (wl12xx_is_roc(wl) &&
2413 !(conf->flags & IEEE80211_CONF_IDLE)) {
2414 ret = wl12xx_croc(wl, wl->dev_role_id);
2415 if (ret < 0)
2416 goto out_sleep;
2417
2418 ret = wl12xx_roc(wl, wl->dev_role_id);
2419 if (ret < 0)
2420 wl1271_warning("roc failed %d",
2421 ret);
2422 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002423 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002424 }
2425 }
2426
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002427 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002428 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002429 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002430 if (ret < 0)
2431 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002432 }
2433
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002434 /*
2435 * if mac80211 changes the PSM mode, make sure the mode is not
2436 * incorrectly changed after the pspoll failure active window.
2437 */
2438 if (changed & IEEE80211_CONF_CHANGE_PS)
2439 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2440
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002441 if (conf->flags & IEEE80211_CONF_PS &&
2442 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2443 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444
2445 /*
2446 * We enter PSM only if we're already associated.
2447 * If we're not, we'll enter it when joining an SSID,
2448 * through the bss_info_changed() hook.
2449 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002450 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002451 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002452 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002453 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002454 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002456 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002457 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002459 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002460
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002461 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002462 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002463 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 }
2465
2466 if (conf->power_level != wl->power_level) {
2467 ret = wl1271_acx_tx_power(wl, conf->power_level);
2468 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002469 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470
2471 wl->power_level = conf->power_level;
2472 }
2473
2474out_sleep:
2475 wl1271_ps_elp_sleep(wl);
2476
2477out:
2478 mutex_unlock(&wl->mutex);
2479
2480 return ret;
2481}
2482
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002483struct wl1271_filter_params {
2484 bool enabled;
2485 int mc_list_length;
2486 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2487};
2488
Jiri Pirko22bedad32010-04-01 21:22:57 +00002489static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2490 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002491{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002492 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002493 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002494 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002495
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002496 if (unlikely(wl->state == WL1271_STATE_OFF))
2497 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002498
Juuso Oikarinen74441132009-10-13 12:47:53 +03002499 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002500 if (!fp) {
2501 wl1271_error("Out of memory setting filters.");
2502 return 0;
2503 }
2504
2505 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002506 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002507 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2508 fp->enabled = false;
2509 } else {
2510 fp->enabled = true;
2511 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002512 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002513 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002514 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002515 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002516 }
2517
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002518 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002519}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002521#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2522 FIF_ALLMULTI | \
2523 FIF_FCSFAIL | \
2524 FIF_BCN_PRBRESP_PROMISC | \
2525 FIF_CONTROL | \
2526 FIF_OTHER_BSS)
2527
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2529 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002530 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002532 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002534 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535
Arik Nemtsov7d057862010-10-16 19:25:35 +02002536 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2537 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002539 mutex_lock(&wl->mutex);
2540
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002541 *total &= WL1271_SUPPORTED_FILTERS;
2542 changed &= WL1271_SUPPORTED_FILTERS;
2543
2544 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002545 goto out;
2546
Ido Yariva6208652011-03-01 15:14:41 +02002547 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002548 if (ret < 0)
2549 goto out;
2550
Arik Nemtsov7d057862010-10-16 19:25:35 +02002551 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2552 if (*total & FIF_ALLMULTI)
2553 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2554 else if (fp)
2555 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2556 fp->mc_list,
2557 fp->mc_list_length);
2558 if (ret < 0)
2559 goto out_sleep;
2560 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002561
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002562 /*
2563 * the fw doesn't provide an api to configure the filters. instead,
2564 * the filters configuration is based on the active roles / ROC
2565 * state.
2566 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002567
2568out_sleep:
2569 wl1271_ps_elp_sleep(wl);
2570
2571out:
2572 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002573 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002574}
2575
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002576static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2577 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2578 u16 tx_seq_16)
2579{
2580 struct wl1271_ap_key *ap_key;
2581 int i;
2582
2583 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2584
2585 if (key_size > MAX_KEY_SIZE)
2586 return -EINVAL;
2587
2588 /*
2589 * Find next free entry in ap_keys. Also check we are not replacing
2590 * an existing key.
2591 */
2592 for (i = 0; i < MAX_NUM_KEYS; i++) {
2593 if (wl->recorded_ap_keys[i] == NULL)
2594 break;
2595
2596 if (wl->recorded_ap_keys[i]->id == id) {
2597 wl1271_warning("trying to record key replacement");
2598 return -EINVAL;
2599 }
2600 }
2601
2602 if (i == MAX_NUM_KEYS)
2603 return -EBUSY;
2604
2605 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2606 if (!ap_key)
2607 return -ENOMEM;
2608
2609 ap_key->id = id;
2610 ap_key->key_type = key_type;
2611 ap_key->key_size = key_size;
2612 memcpy(ap_key->key, key, key_size);
2613 ap_key->hlid = hlid;
2614 ap_key->tx_seq_32 = tx_seq_32;
2615 ap_key->tx_seq_16 = tx_seq_16;
2616
2617 wl->recorded_ap_keys[i] = ap_key;
2618 return 0;
2619}
2620
2621static void wl1271_free_ap_keys(struct wl1271 *wl)
2622{
2623 int i;
2624
2625 for (i = 0; i < MAX_NUM_KEYS; i++) {
2626 kfree(wl->recorded_ap_keys[i]);
2627 wl->recorded_ap_keys[i] = NULL;
2628 }
2629}
2630
2631static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2632{
2633 int i, ret = 0;
2634 struct wl1271_ap_key *key;
2635 bool wep_key_added = false;
2636
2637 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002638 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002639 if (wl->recorded_ap_keys[i] == NULL)
2640 break;
2641
2642 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002643 hlid = key->hlid;
2644 if (hlid == WL12XX_INVALID_LINK_ID)
2645 hlid = wl->ap_bcast_hlid;
2646
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002647 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2648 key->id, key->key_type,
2649 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002650 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002651 key->tx_seq_16);
2652 if (ret < 0)
2653 goto out;
2654
2655 if (key->key_type == KEY_WEP)
2656 wep_key_added = true;
2657 }
2658
2659 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002660 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002661 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002662 if (ret < 0)
2663 goto out;
2664 }
2665
2666out:
2667 wl1271_free_ap_keys(wl);
2668 return ret;
2669}
2670
2671static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2672 u8 key_size, const u8 *key, u32 tx_seq_32,
2673 u16 tx_seq_16, struct ieee80211_sta *sta)
2674{
2675 int ret;
2676 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2677
2678 if (is_ap) {
2679 struct wl1271_station *wl_sta;
2680 u8 hlid;
2681
2682 if (sta) {
2683 wl_sta = (struct wl1271_station *)sta->drv_priv;
2684 hlid = wl_sta->hlid;
2685 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002686 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002687 }
2688
2689 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2690 /*
2691 * We do not support removing keys after AP shutdown.
2692 * Pretend we do to make mac80211 happy.
2693 */
2694 if (action != KEY_ADD_OR_REPLACE)
2695 return 0;
2696
2697 ret = wl1271_record_ap_key(wl, id,
2698 key_type, key_size,
2699 key, hlid, tx_seq_32,
2700 tx_seq_16);
2701 } else {
2702 ret = wl1271_cmd_set_ap_key(wl, action,
2703 id, key_type, key_size,
2704 key, hlid, tx_seq_32,
2705 tx_seq_16);
2706 }
2707
2708 if (ret < 0)
2709 return ret;
2710 } else {
2711 const u8 *addr;
2712 static const u8 bcast_addr[ETH_ALEN] = {
2713 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2714 };
2715
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002716 /*
2717 * A STA set to GEM cipher requires 2 tx spare blocks.
2718 * Return to default value when GEM cipher key is removed
2719 */
2720 if (key_type == KEY_GEM) {
2721 if (action == KEY_ADD_OR_REPLACE)
2722 wl->tx_spare_blocks = 2;
2723 else if (action == KEY_REMOVE)
2724 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2725 }
2726
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 addr = sta ? sta->addr : bcast_addr;
2728
2729 if (is_zero_ether_addr(addr)) {
2730 /* We dont support TX only encryption */
2731 return -EOPNOTSUPP;
2732 }
2733
2734 /* The wl1271 does not allow to remove unicast keys - they
2735 will be cleared automatically on next CMD_JOIN. Ignore the
2736 request silently, as we dont want the mac80211 to emit
2737 an error message. */
2738 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2739 return 0;
2740
Eliad Peller010d3d32011-08-14 13:17:31 +03002741 /* don't remove key if hlid was already deleted */
2742 if (action == KEY_REMOVE &&
2743 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2744 return 0;
2745
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002746 ret = wl1271_cmd_set_sta_key(wl, action,
2747 id, key_type, key_size,
2748 key, addr, tx_seq_32,
2749 tx_seq_16);
2750 if (ret < 0)
2751 return ret;
2752
2753 /* the default WEP key needs to be configured at least once */
2754 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002755 ret = wl12xx_cmd_set_default_wep_key(wl,
2756 wl->default_key,
2757 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002758 if (ret < 0)
2759 return ret;
2760 }
2761 }
2762
2763 return 0;
2764}
2765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2767 struct ieee80211_vif *vif,
2768 struct ieee80211_sta *sta,
2769 struct ieee80211_key_conf *key_conf)
2770{
2771 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002772 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002773 u32 tx_seq_32 = 0;
2774 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002775 u8 key_type;
2776
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002777 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2778
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002780 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002781 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782 key_conf->keylen, key_conf->flags);
2783 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785 mutex_lock(&wl->mutex);
2786
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002787 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2788 ret = -EAGAIN;
2789 goto out_unlock;
2790 }
2791
Ido Yariva6208652011-03-01 15:14:41 +02002792 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 if (ret < 0)
2794 goto out_unlock;
2795
Johannes Berg97359d12010-08-10 09:46:38 +02002796 switch (key_conf->cipher) {
2797 case WLAN_CIPHER_SUITE_WEP40:
2798 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 key_type = KEY_WEP;
2800
2801 key_conf->hw_key_idx = key_conf->keyidx;
2802 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002803 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804 key_type = KEY_TKIP;
2805
2806 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002807 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2808 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002810 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 key_type = KEY_AES;
2812
2813 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002814 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2815 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002816 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002817 case WL1271_CIPHER_SUITE_GEM:
2818 key_type = KEY_GEM;
2819 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2820 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2821 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002822 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002823 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824
2825 ret = -EOPNOTSUPP;
2826 goto out_sleep;
2827 }
2828
2829 switch (cmd) {
2830 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002831 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2832 key_conf->keyidx, key_type,
2833 key_conf->keylen, key_conf->key,
2834 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002835 if (ret < 0) {
2836 wl1271_error("Could not add or replace key");
2837 goto out_sleep;
2838 }
2839 break;
2840
2841 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 ret = wl1271_set_key(wl, KEY_REMOVE,
2843 key_conf->keyidx, key_type,
2844 key_conf->keylen, key_conf->key,
2845 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846 if (ret < 0) {
2847 wl1271_error("Could not remove key");
2848 goto out_sleep;
2849 }
2850 break;
2851
2852 default:
2853 wl1271_error("Unsupported key cmd 0x%x", cmd);
2854 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855 break;
2856 }
2857
2858out_sleep:
2859 wl1271_ps_elp_sleep(wl);
2860
2861out_unlock:
2862 mutex_unlock(&wl->mutex);
2863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002864 return ret;
2865}
2866
2867static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002868 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002869 struct cfg80211_scan_request *req)
2870{
2871 struct wl1271 *wl = hw->priv;
2872 int ret;
2873 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002874 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002875
2876 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2877
2878 if (req->n_ssids) {
2879 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002880 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002881 }
2882
2883 mutex_lock(&wl->mutex);
2884
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002885 if (wl->state == WL1271_STATE_OFF) {
2886 /*
2887 * We cannot return -EBUSY here because cfg80211 will expect
2888 * a call to ieee80211_scan_completed if we do - in this case
2889 * there won't be any call.
2890 */
2891 ret = -EAGAIN;
2892 goto out;
2893 }
2894
Ido Yariva6208652011-03-01 15:14:41 +02002895 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002896 if (ret < 0)
2897 goto out;
2898
Eliad Peller251c1772011-08-14 13:17:17 +03002899 /* cancel ROC before scanning */
2900 if (wl12xx_is_roc(wl)) {
2901 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2902 /* don't allow scanning right now */
2903 ret = -EBUSY;
2904 goto out_sleep;
2905 }
2906 wl12xx_croc(wl, wl->dev_role_id);
2907 wl12xx_cmd_role_stop_dev(wl);
2908 }
2909
Eliad Peller784f6942011-10-05 11:55:39 +02002910 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002911out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913out:
2914 mutex_unlock(&wl->mutex);
2915
2916 return ret;
2917}
2918
Eliad Peller73ecce32011-06-27 13:06:45 +03002919static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2920 struct ieee80211_vif *vif)
2921{
2922 struct wl1271 *wl = hw->priv;
2923 int ret;
2924
2925 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2926
2927 mutex_lock(&wl->mutex);
2928
2929 if (wl->state == WL1271_STATE_OFF)
2930 goto out;
2931
2932 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2933 goto out;
2934
2935 ret = wl1271_ps_elp_wakeup(wl);
2936 if (ret < 0)
2937 goto out;
2938
2939 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2940 ret = wl1271_scan_stop(wl);
2941 if (ret < 0)
2942 goto out_sleep;
2943 }
2944 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2945 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002946 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03002947 wl->scan.req = NULL;
2948 ieee80211_scan_completed(wl->hw, true);
2949
2950out_sleep:
2951 wl1271_ps_elp_sleep(wl);
2952out:
2953 mutex_unlock(&wl->mutex);
2954
2955 cancel_delayed_work_sync(&wl->scan_complete_work);
2956}
2957
Luciano Coelho33c2c062011-05-10 14:46:02 +03002958static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2959 struct ieee80211_vif *vif,
2960 struct cfg80211_sched_scan_request *req,
2961 struct ieee80211_sched_scan_ies *ies)
2962{
2963 struct wl1271 *wl = hw->priv;
2964 int ret;
2965
2966 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2967
2968 mutex_lock(&wl->mutex);
2969
2970 ret = wl1271_ps_elp_wakeup(wl);
2971 if (ret < 0)
2972 goto out;
2973
2974 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2975 if (ret < 0)
2976 goto out_sleep;
2977
2978 ret = wl1271_scan_sched_scan_start(wl);
2979 if (ret < 0)
2980 goto out_sleep;
2981
2982 wl->sched_scanning = true;
2983
2984out_sleep:
2985 wl1271_ps_elp_sleep(wl);
2986out:
2987 mutex_unlock(&wl->mutex);
2988 return ret;
2989}
2990
2991static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2992 struct ieee80211_vif *vif)
2993{
2994 struct wl1271 *wl = hw->priv;
2995 int ret;
2996
2997 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2998
2999 mutex_lock(&wl->mutex);
3000
3001 ret = wl1271_ps_elp_wakeup(wl);
3002 if (ret < 0)
3003 goto out;
3004
3005 wl1271_scan_sched_scan_stop(wl);
3006
3007 wl1271_ps_elp_sleep(wl);
3008out:
3009 mutex_unlock(&wl->mutex);
3010}
3011
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003012static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3013{
3014 struct wl1271 *wl = hw->priv;
3015 int ret = 0;
3016
3017 mutex_lock(&wl->mutex);
3018
3019 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3020 ret = -EAGAIN;
3021 goto out;
3022 }
3023
Ido Yariva6208652011-03-01 15:14:41 +02003024 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003025 if (ret < 0)
3026 goto out;
3027
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003028 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003029 if (ret < 0)
3030 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3031
3032 wl1271_ps_elp_sleep(wl);
3033
3034out:
3035 mutex_unlock(&wl->mutex);
3036
3037 return ret;
3038}
3039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3041{
3042 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003043 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044
3045 mutex_lock(&wl->mutex);
3046
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003047 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3048 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003049 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003050 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003051
Ido Yariva6208652011-03-01 15:14:41 +02003052 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053 if (ret < 0)
3054 goto out;
3055
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003056 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003057 if (ret < 0)
3058 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3059
3060 wl1271_ps_elp_sleep(wl);
3061
3062out:
3063 mutex_unlock(&wl->mutex);
3064
3065 return ret;
3066}
3067
Arik Nemtsove78a2872010-10-16 19:07:21 +02003068static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003069 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003070{
Eliad Peller889cb362011-05-01 09:56:45 +03003071 u8 ssid_len;
3072 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3073 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003074
Eliad Peller889cb362011-05-01 09:56:45 +03003075 if (!ptr) {
3076 wl1271_error("No SSID in IEs!");
3077 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003078 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003079
Eliad Peller889cb362011-05-01 09:56:45 +03003080 ssid_len = ptr[1];
3081 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3082 wl1271_error("SSID is too long!");
3083 return -EINVAL;
3084 }
3085
3086 wl->ssid_len = ssid_len;
3087 memcpy(wl->ssid, ptr+2, ssid_len);
3088 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003089}
3090
Eliad Pellerd48055d2011-09-15 12:07:04 +03003091static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3092{
3093 int len;
3094 const u8 *next, *end = skb->data + skb->len;
3095 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3096 skb->len - ieoffset);
3097 if (!ie)
3098 return;
3099 len = ie[1] + 2;
3100 next = ie + len;
3101 memmove(ie, next, end - next);
3102 skb_trim(skb, skb->len - len);
3103}
3104
Eliad Peller26b4bf22011-09-15 12:07:05 +03003105static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3106 unsigned int oui, u8 oui_type,
3107 int ieoffset)
3108{
3109 int len;
3110 const u8 *next, *end = skb->data + skb->len;
3111 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3112 skb->data + ieoffset,
3113 skb->len - ieoffset);
3114 if (!ie)
3115 return;
3116 len = ie[1] + 2;
3117 next = ie + len;
3118 memmove(ie, next, end - next);
3119 skb_trim(skb, skb->len - len);
3120}
3121
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003122static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
3123 u8 *probe_rsp_data,
3124 size_t probe_rsp_len,
3125 u32 rates)
3126{
3127 struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
3128 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3129 int ssid_ie_offset, ie_offset, templ_len;
3130 const u8 *ptr;
3131
3132 /* no need to change probe response if the SSID is set correctly */
3133 if (wl->ssid_len > 0)
3134 return wl1271_cmd_template_set(wl,
3135 CMD_TEMPL_AP_PROBE_RESPONSE,
3136 probe_rsp_data,
3137 probe_rsp_len, 0,
3138 rates);
3139
3140 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3141 wl1271_error("probe_rsp template too big");
3142 return -EINVAL;
3143 }
3144
3145 /* start searching from IE offset */
3146 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3147
3148 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3149 probe_rsp_len - ie_offset);
3150 if (!ptr) {
3151 wl1271_error("No SSID in beacon!");
3152 return -EINVAL;
3153 }
3154
3155 ssid_ie_offset = ptr - probe_rsp_data;
3156 ptr += (ptr[1] + 2);
3157
3158 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3159
3160 /* insert SSID from bss_conf */
3161 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3162 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3163 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3164 bss_conf->ssid, bss_conf->ssid_len);
3165 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3166
3167 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3168 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3169 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3170
3171 return wl1271_cmd_template_set(wl,
3172 CMD_TEMPL_AP_PROBE_RESPONSE,
3173 probe_rsp_templ,
3174 templ_len, 0,
3175 rates);
3176}
3177
Arik Nemtsove78a2872010-10-16 19:07:21 +02003178static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3179 struct ieee80211_bss_conf *bss_conf,
3180 u32 changed)
3181{
3182 int ret = 0;
3183
3184 if (changed & BSS_CHANGED_ERP_SLOT) {
3185 if (bss_conf->use_short_slot)
3186 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3187 else
3188 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3189 if (ret < 0) {
3190 wl1271_warning("Set slot time failed %d", ret);
3191 goto out;
3192 }
3193 }
3194
3195 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3196 if (bss_conf->use_short_preamble)
3197 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3198 else
3199 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3200 }
3201
3202 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3203 if (bss_conf->use_cts_prot)
3204 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3205 else
3206 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3207 if (ret < 0) {
3208 wl1271_warning("Set ctsprotect failed %d", ret);
3209 goto out;
3210 }
3211 }
3212
3213out:
3214 return ret;
3215}
3216
3217static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3218 struct ieee80211_vif *vif,
3219 struct ieee80211_bss_conf *bss_conf,
3220 u32 changed)
3221{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003222 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003223 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3224 int ret = 0;
3225
3226 if ((changed & BSS_CHANGED_BEACON_INT)) {
3227 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3228 bss_conf->beacon_int);
3229
3230 wl->beacon_int = bss_conf->beacon_int;
3231 }
3232
3233 if ((changed & BSS_CHANGED_BEACON)) {
3234 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003235 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003236 int ieoffset = offsetof(struct ieee80211_mgmt,
3237 u.beacon.variable);
3238 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3239 u16 tmpl_id;
3240
3241 if (!beacon)
3242 goto out;
3243
3244 wl1271_debug(DEBUG_MASTER, "beacon updated");
3245
3246 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3247 if (ret < 0) {
3248 dev_kfree_skb(beacon);
3249 goto out;
3250 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003251 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003252 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3253 CMD_TEMPL_BEACON;
3254 ret = wl1271_cmd_template_set(wl, tmpl_id,
3255 beacon->data,
3256 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003257 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003258 if (ret < 0) {
3259 dev_kfree_skb(beacon);
3260 goto out;
3261 }
3262
Eliad Pellerd48055d2011-09-15 12:07:04 +03003263 /* remove TIM ie from probe response */
3264 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3265
Eliad Peller26b4bf22011-09-15 12:07:05 +03003266 /*
3267 * remove p2p ie from probe response.
3268 * the fw reponds to probe requests that don't include
3269 * the p2p ie. probe requests with p2p ie will be passed,
3270 * and will be responded by the supplicant (the spec
3271 * forbids including the p2p ie when responding to probe
3272 * requests that didn't include it).
3273 */
3274 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3275 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3276
Arik Nemtsove78a2872010-10-16 19:07:21 +02003277 hdr = (struct ieee80211_hdr *) beacon->data;
3278 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3279 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003280 if (is_ap)
3281 ret = wl1271_ap_set_probe_resp_tmpl(wl,
3282 beacon->data,
3283 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003284 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003285 else
3286 ret = wl1271_cmd_template_set(wl,
3287 CMD_TEMPL_PROBE_RESPONSE,
3288 beacon->data,
3289 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003290 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003291 dev_kfree_skb(beacon);
3292 if (ret < 0)
3293 goto out;
3294 }
3295
3296out:
3297 return ret;
3298}
3299
3300/* AP mode changes */
3301static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 struct ieee80211_vif *vif,
3303 struct ieee80211_bss_conf *bss_conf,
3304 u32 changed)
3305{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003306 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003307 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308
Arik Nemtsove78a2872010-10-16 19:07:21 +02003309 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3310 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311
Eliad Peller87fbcb02011-10-05 11:55:41 +02003312 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003313 wl->band);
3314 wl->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003315 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316
Eliad Peller87fbcb02011-10-05 11:55:41 +02003317 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003318 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003319 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003320 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003321 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003322
Eliad Peller784f6942011-10-05 11:55:39 +02003323 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003324 if (ret < 0)
3325 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003326 }
3327
Arik Nemtsove78a2872010-10-16 19:07:21 +02003328 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3329 if (ret < 0)
3330 goto out;
3331
3332 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3333 if (bss_conf->enable_beacon) {
3334 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003335 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003336 if (ret < 0)
3337 goto out;
3338
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003339 ret = wl1271_ap_init_hwenc(wl);
3340 if (ret < 0)
3341 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003342
3343 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3344 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 }
3346 } else {
3347 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003348 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 if (ret < 0)
3350 goto out;
3351
3352 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3353 wl1271_debug(DEBUG_AP, "stopped AP");
3354 }
3355 }
3356 }
3357
3358 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3359 if (ret < 0)
3360 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003361
3362 /* Handle HT information change */
3363 if ((changed & BSS_CHANGED_HT) &&
3364 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3365 ret = wl1271_acx_set_ht_information(wl,
3366 bss_conf->ht_operation_mode);
3367 if (ret < 0) {
3368 wl1271_warning("Set ht information failed %d", ret);
3369 goto out;
3370 }
3371 }
3372
Arik Nemtsove78a2872010-10-16 19:07:21 +02003373out:
3374 return;
3375}
3376
3377/* STA/IBSS mode changes */
3378static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3379 struct ieee80211_vif *vif,
3380 struct ieee80211_bss_conf *bss_conf,
3381 u32 changed)
3382{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003383 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 bool do_join = false, set_assoc = false;
3385 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003386 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003387 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003389 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003390 bool sta_exists = false;
3391 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392
3393 if (is_ibss) {
3394 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3395 changed);
3396 if (ret < 0)
3397 goto out;
3398 }
3399
Eliad Peller227e81e2011-08-14 13:17:26 +03003400 if (changed & BSS_CHANGED_IBSS) {
3401 if (bss_conf->ibss_joined) {
3402 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3403 ibss_joined = true;
3404 } else {
3405 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3406 &wl->flags)) {
3407 wl1271_unjoin(wl);
3408 wl12xx_cmd_role_start_dev(wl);
3409 wl12xx_roc(wl, wl->dev_role_id);
3410 }
3411 }
3412 }
3413
3414 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003415 do_join = true;
3416
3417 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003418 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003419 do_join = true;
3420
Eliad Peller227e81e2011-08-14 13:17:26 +03003421 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003422 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3423 bss_conf->enable_beacon ? "enabled" : "disabled");
3424
3425 if (bss_conf->enable_beacon)
3426 wl->set_bss_type = BSS_TYPE_IBSS;
3427 else
3428 wl->set_bss_type = BSS_TYPE_STA_BSS;
3429 do_join = true;
3430 }
3431
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003433 bool enable = false;
3434 if (bss_conf->cqm_rssi_thold)
3435 enable = true;
3436 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3437 bss_conf->cqm_rssi_thold,
3438 bss_conf->cqm_rssi_hyst);
3439 if (ret < 0)
3440 goto out;
3441 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3442 }
3443
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003444 if ((changed & BSS_CHANGED_BSSID) &&
3445 /*
3446 * Now we know the correct bssid, so we send a new join command
3447 * and enable the BSSID filter
3448 */
3449 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003450 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003451
Eliad Pellerfa287b82010-12-26 09:27:50 +01003452 if (!is_zero_ether_addr(wl->bssid)) {
3453 ret = wl1271_cmd_build_null_data(wl);
3454 if (ret < 0)
3455 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003456
Eliad Peller784f6942011-10-05 11:55:39 +02003457 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003458 if (ret < 0)
3459 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003460
Eliad Pellerfa287b82010-12-26 09:27:50 +01003461 /* Need to update the BSSID (for filtering etc) */
3462 do_join = true;
3463 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003464 }
3465
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003466 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3467 rcu_read_lock();
3468 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3469 if (!sta)
3470 goto sta_not_found;
3471
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003472 /* save the supp_rates of the ap */
3473 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3474 if (sta->ht_cap.ht_supported)
3475 sta_rate_set |=
3476 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003477 sta_ht_cap = sta->ht_cap;
3478 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003479
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003480sta_not_found:
3481 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003482 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003483
Arik Nemtsove78a2872010-10-16 19:07:21 +02003484 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003486 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003487 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003488 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003489 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003490
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003491 wl->ps_poll_failures = 0;
3492
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003493 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003494 * use basic rates from AP, and determine lowest rate
3495 * to use with control frames.
3496 */
3497 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003498 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003499 wl1271_tx_enabled_rates_get(wl, rates,
3500 wl->band);
3501 wl->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 wl1271_tx_min_rate_get(wl,
3503 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003504 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003505 wlvif->rate_set =
3506 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003507 sta_rate_set,
3508 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003509 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003510 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003512
3513 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003514 * with wl1271, we don't need to update the
3515 * beacon_int and dtim_period, because the firmware
3516 * updates it by itself when the first beacon is
3517 * received after a join.
3518 */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003519 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wl->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003520 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003522
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003523 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003524 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003525 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003526 dev_kfree_skb(wl->probereq);
3527 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3528 ieoffset = offsetof(struct ieee80211_mgmt,
3529 u.probe_req.variable);
3530 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003531
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003532 /* enable the connection monitoring feature */
3533 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003534 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003536 } else {
3537 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003538 bool was_assoc =
3539 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3540 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003541 bool was_ifup =
3542 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3543 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003544 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003545
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003546 /* free probe-request template */
3547 dev_kfree_skb(wl->probereq);
3548 wl->probereq = NULL;
3549
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003550 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003551 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003552
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003553 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003554 wl1271_set_band_rate(wl, wlvif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003555 wl->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003556 wl1271_tx_min_rate_get(wl,
3557 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003558 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003559 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003560 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003561
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003562 /* disable connection monitor features */
3563 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003564
3565 /* Disable the keep-alive feature */
3566 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003567 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003569
3570 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003571 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003572 u32 conf_flags = wl->hw->conf.flags;
3573 /*
3574 * we might have to disable roc, if there was
3575 * no IF_OPER_UP notification.
3576 */
3577 if (!was_ifup) {
3578 ret = wl12xx_croc(wl, wl->role_id);
3579 if (ret < 0)
3580 goto out;
3581 }
3582 /*
3583 * (we also need to disable roc in case of
3584 * roaming on the same channel. until we will
3585 * have a better flow...)
3586 */
3587 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3588 ret = wl12xx_croc(wl, wl->dev_role_id);
3589 if (ret < 0)
3590 goto out;
3591 }
3592
Eliad Peller30df14d2011-04-05 19:13:28 +03003593 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003594 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3595 wl12xx_cmd_role_start_dev(wl);
3596 wl12xx_roc(wl, wl->dev_role_id);
3597 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003598 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003599 }
3600 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003601
Eliad Pellerd192d262011-05-24 14:33:08 +03003602 if (changed & BSS_CHANGED_IBSS) {
3603 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3604 bss_conf->ibss_joined);
3605
3606 if (bss_conf->ibss_joined) {
3607 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003608 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003609 wl1271_tx_enabled_rates_get(wl, rates,
3610 wl->band);
3611 wl->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003612 wl1271_tx_min_rate_get(wl,
3613 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003614
Shahar Levi06b660e2011-09-05 13:54:36 +03003615 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003616 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3617 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003618 if (ret < 0)
3619 goto out;
3620 }
3621 }
3622
Arik Nemtsove78a2872010-10-16 19:07:21 +02003623 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3624 if (ret < 0)
3625 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003626
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003627 if (changed & BSS_CHANGED_ARP_FILTER) {
3628 __be32 addr = bss_conf->arp_addr_list[0];
3629 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3630
Eliad Pellerc5312772010-12-09 11:31:27 +02003631 if (bss_conf->arp_addr_cnt == 1 &&
3632 bss_conf->arp_filter_enabled) {
3633 /*
3634 * The template should have been configured only upon
3635 * association. however, it seems that the correct ip
3636 * isn't being set (when sending), so we have to
3637 * reconfigure the template upon every ip change.
3638 */
3639 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3640 if (ret < 0) {
3641 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003642 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003643 }
3644
3645 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003646 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003647 addr);
3648 } else
3649 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003650
3651 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003652 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003653 }
3654
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003655 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003656 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003657 if (ret < 0) {
3658 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003659 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003660 }
Eliad Peller251c1772011-08-14 13:17:17 +03003661
3662 /* ROC until connected (after EAPOL exchange) */
3663 if (!is_ibss) {
3664 ret = wl12xx_roc(wl, wl->role_id);
3665 if (ret < 0)
3666 goto out;
3667
3668 wl1271_check_operstate(wl,
3669 ieee80211_get_operstate(vif));
3670 }
3671 /*
3672 * stop device role if started (we might already be in
3673 * STA role). TODO: make it better.
3674 */
3675 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3676 ret = wl12xx_croc(wl, wl->dev_role_id);
3677 if (ret < 0)
3678 goto out;
3679
3680 ret = wl12xx_cmd_role_stop_dev(wl);
3681 if (ret < 0)
3682 goto out;
3683 }
Eliad Peller05dba352011-08-23 16:37:01 +03003684
3685 /* If we want to go in PSM but we're not there yet */
3686 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3687 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3688 enum wl1271_cmd_ps_mode mode;
3689
3690 mode = STATION_POWER_SAVE_MODE;
3691 ret = wl1271_ps_set_mode(wl, mode,
3692 wl->basic_rate,
3693 true);
3694 if (ret < 0)
3695 goto out;
3696 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003697 }
3698
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003699 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003700 if (sta_exists) {
3701 if ((changed & BSS_CHANGED_HT) &&
3702 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003703 ret = wl1271_acx_set_ht_capabilities(wl,
3704 &sta_ht_cap,
3705 true,
3706 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003707 if (ret < 0) {
3708 wl1271_warning("Set ht cap true failed %d",
3709 ret);
3710 goto out;
3711 }
3712 }
3713 /* handle new association without HT and disassociation */
3714 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003715 ret = wl1271_acx_set_ht_capabilities(wl,
3716 &sta_ht_cap,
3717 false,
3718 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003719 if (ret < 0) {
3720 wl1271_warning("Set ht cap false failed %d",
3721 ret);
3722 goto out;
3723 }
3724 }
3725 }
3726
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003727 /* Handle HT information change. Done after join. */
3728 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003729 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3730 ret = wl1271_acx_set_ht_information(wl,
3731 bss_conf->ht_operation_mode);
3732 if (ret < 0) {
3733 wl1271_warning("Set ht information failed %d", ret);
3734 goto out;
3735 }
3736 }
3737
Arik Nemtsove78a2872010-10-16 19:07:21 +02003738out:
3739 return;
3740}
3741
3742static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3743 struct ieee80211_vif *vif,
3744 struct ieee80211_bss_conf *bss_conf,
3745 u32 changed)
3746{
3747 struct wl1271 *wl = hw->priv;
3748 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3749 int ret;
3750
3751 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3752 (int)changed);
3753
3754 mutex_lock(&wl->mutex);
3755
3756 if (unlikely(wl->state == WL1271_STATE_OFF))
3757 goto out;
3758
Ido Yariva6208652011-03-01 15:14:41 +02003759 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003760 if (ret < 0)
3761 goto out;
3762
3763 if (is_ap)
3764 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3765 else
3766 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3767
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003768 wl1271_ps_elp_sleep(wl);
3769
3770out:
3771 mutex_unlock(&wl->mutex);
3772}
3773
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003774static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3775 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003776 const struct ieee80211_tx_queue_params *params)
3777{
3778 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003779 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003780 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003781
3782 mutex_lock(&wl->mutex);
3783
3784 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3785
Kalle Valo4695dc92010-03-18 12:26:38 +02003786 if (params->uapsd)
3787 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3788 else
3789 ps_scheme = CONF_PS_SCHEME_LEGACY;
3790
Arik Nemtsov488fc542010-10-16 20:33:45 +02003791 if (wl->state == WL1271_STATE_OFF) {
3792 /*
3793 * If the state is off, the parameters will be recorded and
3794 * configured on init. This happens in AP-mode.
3795 */
3796 struct conf_tx_ac_category *conf_ac =
3797 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3798 struct conf_tx_tid *conf_tid =
3799 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3800
3801 conf_ac->ac = wl1271_tx_get_queue(queue);
3802 conf_ac->cw_min = (u8)params->cw_min;
3803 conf_ac->cw_max = params->cw_max;
3804 conf_ac->aifsn = params->aifs;
3805 conf_ac->tx_op_limit = params->txop << 5;
3806
3807 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3808 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3809 conf_tid->tsid = wl1271_tx_get_queue(queue);
3810 conf_tid->ps_scheme = ps_scheme;
3811 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3812 conf_tid->apsd_conf[0] = 0;
3813 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003814 goto out;
3815 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003816
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003817 ret = wl1271_ps_elp_wakeup(wl);
3818 if (ret < 0)
3819 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003820
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003821 /*
3822 * the txop is confed in units of 32us by the mac80211,
3823 * we need us
3824 */
3825 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3826 params->cw_min, params->cw_max,
3827 params->aifs, params->txop << 5);
3828 if (ret < 0)
3829 goto out_sleep;
3830
3831 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3832 CONF_CHANNEL_TYPE_EDCF,
3833 wl1271_tx_get_queue(queue),
3834 ps_scheme, CONF_ACK_POLICY_LEGACY,
3835 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003836
3837out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003838 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003839
3840out:
3841 mutex_unlock(&wl->mutex);
3842
3843 return ret;
3844}
3845
Eliad Peller37a41b42011-09-21 14:06:11 +03003846static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3847 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003848{
3849
3850 struct wl1271 *wl = hw->priv;
3851 u64 mactime = ULLONG_MAX;
3852 int ret;
3853
3854 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3855
3856 mutex_lock(&wl->mutex);
3857
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003858 if (unlikely(wl->state == WL1271_STATE_OFF))
3859 goto out;
3860
Ido Yariva6208652011-03-01 15:14:41 +02003861 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003862 if (ret < 0)
3863 goto out;
3864
3865 ret = wl1271_acx_tsf_info(wl, &mactime);
3866 if (ret < 0)
3867 goto out_sleep;
3868
3869out_sleep:
3870 wl1271_ps_elp_sleep(wl);
3871
3872out:
3873 mutex_unlock(&wl->mutex);
3874 return mactime;
3875}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003876
John W. Linvilleece550d2010-07-28 16:41:06 -04003877static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3878 struct survey_info *survey)
3879{
3880 struct wl1271 *wl = hw->priv;
3881 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003882
John W. Linvilleece550d2010-07-28 16:41:06 -04003883 if (idx != 0)
3884 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003885
John W. Linvilleece550d2010-07-28 16:41:06 -04003886 survey->channel = conf->channel;
3887 survey->filled = SURVEY_INFO_NOISE_DBM;
3888 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003889
John W. Linvilleece550d2010-07-28 16:41:06 -04003890 return 0;
3891}
3892
Arik Nemtsov409622e2011-02-23 00:22:29 +02003893static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003894 struct ieee80211_sta *sta,
3895 u8 *hlid)
3896{
3897 struct wl1271_station *wl_sta;
3898 int id;
3899
3900 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3901 if (id >= AP_MAX_STATIONS) {
3902 wl1271_warning("could not allocate HLID - too much stations");
3903 return -EBUSY;
3904 }
3905
3906 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003907 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003908 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3909 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003910 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003911 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003912 return 0;
3913}
3914
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003915void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003916{
3917 int id = hlid - WL1271_AP_STA_HLID_START;
3918
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003919 if (hlid < WL1271_AP_STA_HLID_START)
3920 return;
3921
3922 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003923 return;
3924
Arik Nemtsov04216da2011-08-14 13:17:38 +03003925 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003926 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003927 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003928 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003929 __clear_bit(hlid, &wl->ap_ps_map);
3930 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003931 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003932}
3933
3934static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3935 struct ieee80211_vif *vif,
3936 struct ieee80211_sta *sta)
3937{
3938 struct wl1271 *wl = hw->priv;
3939 int ret = 0;
3940 u8 hlid;
3941
3942 mutex_lock(&wl->mutex);
3943
3944 if (unlikely(wl->state == WL1271_STATE_OFF))
3945 goto out;
3946
3947 if (wl->bss_type != BSS_TYPE_AP_BSS)
3948 goto out;
3949
3950 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3951
Arik Nemtsov409622e2011-02-23 00:22:29 +02003952 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003953 if (ret < 0)
3954 goto out;
3955
Ido Yariva6208652011-03-01 15:14:41 +02003956 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003957 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003958 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003959
Eliad Pellerc690ec82011-08-14 13:17:07 +03003960 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003961 if (ret < 0)
3962 goto out_sleep;
3963
Eliad Pellerb67476e2011-08-14 13:17:23 +03003964 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3965 if (ret < 0)
3966 goto out_sleep;
3967
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003968 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3969 if (ret < 0)
3970 goto out_sleep;
3971
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003972out_sleep:
3973 wl1271_ps_elp_sleep(wl);
3974
Arik Nemtsov409622e2011-02-23 00:22:29 +02003975out_free_sta:
3976 if (ret < 0)
3977 wl1271_free_sta(wl, hlid);
3978
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003979out:
3980 mutex_unlock(&wl->mutex);
3981 return ret;
3982}
3983
3984static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3985 struct ieee80211_vif *vif,
3986 struct ieee80211_sta *sta)
3987{
3988 struct wl1271 *wl = hw->priv;
3989 struct wl1271_station *wl_sta;
3990 int ret = 0, id;
3991
3992 mutex_lock(&wl->mutex);
3993
3994 if (unlikely(wl->state == WL1271_STATE_OFF))
3995 goto out;
3996
3997 if (wl->bss_type != BSS_TYPE_AP_BSS)
3998 goto out;
3999
4000 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4001
4002 wl_sta = (struct wl1271_station *)sta->drv_priv;
4003 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
4004 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
4005 goto out;
4006
Ido Yariva6208652011-03-01 15:14:41 +02004007 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004008 if (ret < 0)
4009 goto out;
4010
Eliad Pellerc690ec82011-08-14 13:17:07 +03004011 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004012 if (ret < 0)
4013 goto out_sleep;
4014
Arik Nemtsov409622e2011-02-23 00:22:29 +02004015 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004016
4017out_sleep:
4018 wl1271_ps_elp_sleep(wl);
4019
4020out:
4021 mutex_unlock(&wl->mutex);
4022 return ret;
4023}
4024
Luciano Coelho4623ec72011-03-21 19:26:41 +02004025static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4026 struct ieee80211_vif *vif,
4027 enum ieee80211_ampdu_mlme_action action,
4028 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4029 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004030{
4031 struct wl1271 *wl = hw->priv;
4032 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004033 u8 hlid, *ba_bitmap;
4034
4035 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4036 tid);
4037
4038 /* sanity check - the fields in FW are only 8bits wide */
4039 if (WARN_ON(tid > 0xFF))
4040 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004041
4042 mutex_lock(&wl->mutex);
4043
4044 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4045 ret = -EAGAIN;
4046 goto out;
4047 }
4048
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004049 if (wl->bss_type == BSS_TYPE_STA_BSS) {
4050 hlid = wl->sta_hlid;
4051 ba_bitmap = &wl->ba_rx_bitmap;
4052 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
4053 struct wl1271_station *wl_sta;
4054
4055 wl_sta = (struct wl1271_station *)sta->drv_priv;
4056 hlid = wl_sta->hlid;
4057 ba_bitmap = &wl->links[hlid].ba_bitmap;
4058 } else {
4059 ret = -EINVAL;
4060 goto out;
4061 }
4062
Ido Yariva6208652011-03-01 15:14:41 +02004063 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004064 if (ret < 0)
4065 goto out;
4066
Shahar Levi70559a02011-05-22 16:10:22 +03004067 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4068 tid, action);
4069
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004070 switch (action) {
4071 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004072 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004073 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004074 break;
4075 }
4076
4077 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4078 ret = -EBUSY;
4079 wl1271_error("exceeded max RX BA sessions");
4080 break;
4081 }
4082
4083 if (*ba_bitmap & BIT(tid)) {
4084 ret = -EINVAL;
4085 wl1271_error("cannot enable RX BA session on active "
4086 "tid: %d", tid);
4087 break;
4088 }
4089
4090 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4091 hlid);
4092 if (!ret) {
4093 *ba_bitmap |= BIT(tid);
4094 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004095 }
4096 break;
4097
4098 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004099 if (!(*ba_bitmap & BIT(tid))) {
4100 ret = -EINVAL;
4101 wl1271_error("no active RX BA session on tid: %d",
4102 tid);
4103 break;
4104 }
4105
4106 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4107 hlid);
4108 if (!ret) {
4109 *ba_bitmap &= ~BIT(tid);
4110 wl->ba_rx_session_count--;
4111 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004112 break;
4113
4114 /*
4115 * The BA initiator session management in FW independently.
4116 * Falling break here on purpose for all TX APDU commands.
4117 */
4118 case IEEE80211_AMPDU_TX_START:
4119 case IEEE80211_AMPDU_TX_STOP:
4120 case IEEE80211_AMPDU_TX_OPERATIONAL:
4121 ret = -EINVAL;
4122 break;
4123
4124 default:
4125 wl1271_error("Incorrect ampdu action id=%x\n", action);
4126 ret = -EINVAL;
4127 }
4128
4129 wl1271_ps_elp_sleep(wl);
4130
4131out:
4132 mutex_unlock(&wl->mutex);
4133
4134 return ret;
4135}
4136
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004137static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4138 struct ieee80211_vif *vif,
4139 const struct cfg80211_bitrate_mask *mask)
4140{
4141 struct wl1271 *wl = hw->priv;
4142 int i;
4143
4144 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4145 mask->control[NL80211_BAND_2GHZ].legacy,
4146 mask->control[NL80211_BAND_5GHZ].legacy);
4147
4148 mutex_lock(&wl->mutex);
4149
4150 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4151 wl->bitrate_masks[i] =
4152 wl1271_tx_enabled_rates_get(wl,
4153 mask->control[i].legacy,
4154 i);
4155 mutex_unlock(&wl->mutex);
4156
4157 return 0;
4158}
4159
Shahar Levi6d158ff2011-09-08 13:01:33 +03004160static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4161 struct ieee80211_channel_switch *ch_switch)
4162{
4163 struct wl1271 *wl = hw->priv;
4164 int ret;
4165
4166 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4167
4168 mutex_lock(&wl->mutex);
4169
4170 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4171 mutex_unlock(&wl->mutex);
4172 ieee80211_chswitch_done(wl->vif, false);
4173 return;
4174 }
4175
4176 ret = wl1271_ps_elp_wakeup(wl);
4177 if (ret < 0)
4178 goto out;
4179
4180 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4181
4182 if (!ret)
4183 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4184
4185 wl1271_ps_elp_sleep(wl);
4186
4187out:
4188 mutex_unlock(&wl->mutex);
4189}
4190
Arik Nemtsov33437892011-04-26 23:35:39 +03004191static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4192{
4193 struct wl1271 *wl = hw->priv;
4194 bool ret = false;
4195
4196 mutex_lock(&wl->mutex);
4197
4198 if (unlikely(wl->state == WL1271_STATE_OFF))
4199 goto out;
4200
4201 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004202 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004203
4204 /* the above is appropriate for STA mode for PS purposes */
4205 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
4206
4207out:
4208 mutex_unlock(&wl->mutex);
4209
4210 return ret;
4211}
4212
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004213/* can't be const, mac80211 writes to this */
4214static struct ieee80211_rate wl1271_rates[] = {
4215 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004216 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4217 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004218 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004219 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4220 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004221 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4222 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004223 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4224 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004225 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4226 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004227 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4228 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004229 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4230 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004231 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4232 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004233 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004234 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4235 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004236 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004237 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4238 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004239 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004240 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4241 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004242 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004243 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4244 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004245 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004246 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4247 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004248 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004249 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4250 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004251 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004252 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4253 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004254};
4255
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004256/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004257static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004258 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004259 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004260 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4261 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4262 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004263 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004264 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4265 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4266 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004267 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004268 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4269 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4270 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004271 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004272};
4273
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004274/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004275static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004276 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004277 7, /* CONF_HW_RXTX_RATE_MCS7 */
4278 6, /* CONF_HW_RXTX_RATE_MCS6 */
4279 5, /* CONF_HW_RXTX_RATE_MCS5 */
4280 4, /* CONF_HW_RXTX_RATE_MCS4 */
4281 3, /* CONF_HW_RXTX_RATE_MCS3 */
4282 2, /* CONF_HW_RXTX_RATE_MCS2 */
4283 1, /* CONF_HW_RXTX_RATE_MCS1 */
4284 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004285
4286 11, /* CONF_HW_RXTX_RATE_54 */
4287 10, /* CONF_HW_RXTX_RATE_48 */
4288 9, /* CONF_HW_RXTX_RATE_36 */
4289 8, /* CONF_HW_RXTX_RATE_24 */
4290
4291 /* TI-specific rate */
4292 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4293
4294 7, /* CONF_HW_RXTX_RATE_18 */
4295 6, /* CONF_HW_RXTX_RATE_12 */
4296 3, /* CONF_HW_RXTX_RATE_11 */
4297 5, /* CONF_HW_RXTX_RATE_9 */
4298 4, /* CONF_HW_RXTX_RATE_6 */
4299 2, /* CONF_HW_RXTX_RATE_5_5 */
4300 1, /* CONF_HW_RXTX_RATE_2 */
4301 0 /* CONF_HW_RXTX_RATE_1 */
4302};
4303
Shahar Levie8b03a22010-10-13 16:09:39 +02004304/* 11n STA capabilities */
4305#define HW_RX_HIGHEST_RATE 72
4306
Shahar Levi00d20102010-11-08 11:20:10 +00004307#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004308 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4309 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004310 .ht_supported = true, \
4311 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4312 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4313 .mcs = { \
4314 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4315 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4316 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4317 }, \
4318}
4319
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004320/* can't be const, mac80211 writes to this */
4321static struct ieee80211_supported_band wl1271_band_2ghz = {
4322 .channels = wl1271_channels,
4323 .n_channels = ARRAY_SIZE(wl1271_channels),
4324 .bitrates = wl1271_rates,
4325 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004326 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004327};
4328
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004329/* 5 GHz data rates for WL1273 */
4330static struct ieee80211_rate wl1271_rates_5ghz[] = {
4331 { .bitrate = 60,
4332 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4333 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4334 { .bitrate = 90,
4335 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4336 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4337 { .bitrate = 120,
4338 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4339 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4340 { .bitrate = 180,
4341 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4342 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4343 { .bitrate = 240,
4344 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4345 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4346 { .bitrate = 360,
4347 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4348 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4349 { .bitrate = 480,
4350 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4351 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4352 { .bitrate = 540,
4353 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4354 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4355};
4356
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004357/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004358static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004359 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4360 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4361 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4362 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4363 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4364 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4365 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4366 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4367 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4368 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4369 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4370 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4371 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4372 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4373 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4374 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4375 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4376 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4377 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4378 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4379 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4380 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4381 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4382 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4383 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4384 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4385 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4386 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4387 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4388 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4389 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4390 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4391 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4392 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004393};
4394
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004395/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004396static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004397 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004398 7, /* CONF_HW_RXTX_RATE_MCS7 */
4399 6, /* CONF_HW_RXTX_RATE_MCS6 */
4400 5, /* CONF_HW_RXTX_RATE_MCS5 */
4401 4, /* CONF_HW_RXTX_RATE_MCS4 */
4402 3, /* CONF_HW_RXTX_RATE_MCS3 */
4403 2, /* CONF_HW_RXTX_RATE_MCS2 */
4404 1, /* CONF_HW_RXTX_RATE_MCS1 */
4405 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004406
4407 7, /* CONF_HW_RXTX_RATE_54 */
4408 6, /* CONF_HW_RXTX_RATE_48 */
4409 5, /* CONF_HW_RXTX_RATE_36 */
4410 4, /* CONF_HW_RXTX_RATE_24 */
4411
4412 /* TI-specific rate */
4413 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4414
4415 3, /* CONF_HW_RXTX_RATE_18 */
4416 2, /* CONF_HW_RXTX_RATE_12 */
4417 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4418 1, /* CONF_HW_RXTX_RATE_9 */
4419 0, /* CONF_HW_RXTX_RATE_6 */
4420 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4421 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4422 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4423};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004424
4425static struct ieee80211_supported_band wl1271_band_5ghz = {
4426 .channels = wl1271_channels_5ghz,
4427 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4428 .bitrates = wl1271_rates_5ghz,
4429 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004430 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004431};
4432
Tobias Klausera0ea9492010-05-20 10:38:11 +02004433static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004434 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4435 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4436};
4437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438static const struct ieee80211_ops wl1271_ops = {
4439 .start = wl1271_op_start,
4440 .stop = wl1271_op_stop,
4441 .add_interface = wl1271_op_add_interface,
4442 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004443#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004444 .suspend = wl1271_op_suspend,
4445 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004446#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004448 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 .configure_filter = wl1271_op_configure_filter,
4450 .tx = wl1271_op_tx,
4451 .set_key = wl1271_op_set_key,
4452 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004453 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004454 .sched_scan_start = wl1271_op_sched_scan_start,
4455 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004457 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004459 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004460 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004461 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004462 .sta_add = wl1271_op_sta_add,
4463 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004464 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004465 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004466 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004467 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004468 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004469};
4470
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004471
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004472u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004473{
4474 u8 idx;
4475
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004476 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004477
4478 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4479 wl1271_error("Illegal RX rate from HW: %d", rate);
4480 return 0;
4481 }
4482
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004483 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004484 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4485 wl1271_error("Unsupported RX rate from HW: %d", rate);
4486 return 0;
4487 }
4488
4489 return idx;
4490}
4491
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004492static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4493 struct device_attribute *attr,
4494 char *buf)
4495{
4496 struct wl1271 *wl = dev_get_drvdata(dev);
4497 ssize_t len;
4498
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004499 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004500
4501 mutex_lock(&wl->mutex);
4502 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4503 wl->sg_enabled);
4504 mutex_unlock(&wl->mutex);
4505
4506 return len;
4507
4508}
4509
4510static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4511 struct device_attribute *attr,
4512 const char *buf, size_t count)
4513{
4514 struct wl1271 *wl = dev_get_drvdata(dev);
4515 unsigned long res;
4516 int ret;
4517
Luciano Coelho6277ed62011-04-01 17:49:54 +03004518 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004519 if (ret < 0) {
4520 wl1271_warning("incorrect value written to bt_coex_mode");
4521 return count;
4522 }
4523
4524 mutex_lock(&wl->mutex);
4525
4526 res = !!res;
4527
4528 if (res == wl->sg_enabled)
4529 goto out;
4530
4531 wl->sg_enabled = res;
4532
4533 if (wl->state == WL1271_STATE_OFF)
4534 goto out;
4535
Ido Yariva6208652011-03-01 15:14:41 +02004536 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004537 if (ret < 0)
4538 goto out;
4539
4540 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4541 wl1271_ps_elp_sleep(wl);
4542
4543 out:
4544 mutex_unlock(&wl->mutex);
4545 return count;
4546}
4547
4548static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4549 wl1271_sysfs_show_bt_coex_state,
4550 wl1271_sysfs_store_bt_coex_state);
4551
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004552static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4553 struct device_attribute *attr,
4554 char *buf)
4555{
4556 struct wl1271 *wl = dev_get_drvdata(dev);
4557 ssize_t len;
4558
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004559 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004560
4561 mutex_lock(&wl->mutex);
4562 if (wl->hw_pg_ver >= 0)
4563 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4564 else
4565 len = snprintf(buf, len, "n/a\n");
4566 mutex_unlock(&wl->mutex);
4567
4568 return len;
4569}
4570
Gery Kahn6f07b722011-07-18 14:21:49 +03004571static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004572 wl1271_sysfs_show_hw_pg_ver, NULL);
4573
Ido Yariv95dac04f2011-06-06 14:57:06 +03004574static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4575 struct bin_attribute *bin_attr,
4576 char *buffer, loff_t pos, size_t count)
4577{
4578 struct device *dev = container_of(kobj, struct device, kobj);
4579 struct wl1271 *wl = dev_get_drvdata(dev);
4580 ssize_t len;
4581 int ret;
4582
4583 ret = mutex_lock_interruptible(&wl->mutex);
4584 if (ret < 0)
4585 return -ERESTARTSYS;
4586
4587 /* Let only one thread read the log at a time, blocking others */
4588 while (wl->fwlog_size == 0) {
4589 DEFINE_WAIT(wait);
4590
4591 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4592 &wait,
4593 TASK_INTERRUPTIBLE);
4594
4595 if (wl->fwlog_size != 0) {
4596 finish_wait(&wl->fwlog_waitq, &wait);
4597 break;
4598 }
4599
4600 mutex_unlock(&wl->mutex);
4601
4602 schedule();
4603 finish_wait(&wl->fwlog_waitq, &wait);
4604
4605 if (signal_pending(current))
4606 return -ERESTARTSYS;
4607
4608 ret = mutex_lock_interruptible(&wl->mutex);
4609 if (ret < 0)
4610 return -ERESTARTSYS;
4611 }
4612
4613 /* Check if the fwlog is still valid */
4614 if (wl->fwlog_size < 0) {
4615 mutex_unlock(&wl->mutex);
4616 return 0;
4617 }
4618
4619 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4620 len = min(count, (size_t)wl->fwlog_size);
4621 wl->fwlog_size -= len;
4622 memcpy(buffer, wl->fwlog, len);
4623
4624 /* Make room for new messages */
4625 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4626
4627 mutex_unlock(&wl->mutex);
4628
4629 return len;
4630}
4631
4632static struct bin_attribute fwlog_attr = {
4633 .attr = {.name = "fwlog", .mode = S_IRUSR},
4634 .read = wl1271_sysfs_read_fwlog,
4635};
4636
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004637int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004638{
4639 int ret;
4640
4641 if (wl->mac80211_registered)
4642 return 0;
4643
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004644 ret = wl1271_fetch_nvs(wl);
4645 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004646 /* NOTE: The wl->nvs->nvs element must be first, in
4647 * order to simplify the casting, we assume it is at
4648 * the beginning of the wl->nvs structure.
4649 */
4650 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004651
4652 wl->mac_addr[0] = nvs_ptr[11];
4653 wl->mac_addr[1] = nvs_ptr[10];
4654 wl->mac_addr[2] = nvs_ptr[6];
4655 wl->mac_addr[3] = nvs_ptr[5];
4656 wl->mac_addr[4] = nvs_ptr[4];
4657 wl->mac_addr[5] = nvs_ptr[3];
4658 }
4659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4661
4662 ret = ieee80211_register_hw(wl->hw);
4663 if (ret < 0) {
4664 wl1271_error("unable to register mac80211 hw: %d", ret);
4665 return ret;
4666 }
4667
4668 wl->mac80211_registered = true;
4669
Eliad Pellerd60080a2010-11-24 12:53:16 +02004670 wl1271_debugfs_init(wl);
4671
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004672 register_netdevice_notifier(&wl1271_dev_notifier);
4673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004674 wl1271_notice("loaded");
4675
4676 return 0;
4677}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004678EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004679
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004680void wl1271_unregister_hw(struct wl1271 *wl)
4681{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004682 if (wl->state == WL1271_STATE_PLT)
4683 __wl1271_plt_stop(wl);
4684
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004685 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004686 ieee80211_unregister_hw(wl->hw);
4687 wl->mac80211_registered = false;
4688
4689}
4690EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4691
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004692int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004693{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004694 static const u32 cipher_suites[] = {
4695 WLAN_CIPHER_SUITE_WEP40,
4696 WLAN_CIPHER_SUITE_WEP104,
4697 WLAN_CIPHER_SUITE_TKIP,
4698 WLAN_CIPHER_SUITE_CCMP,
4699 WL1271_CIPHER_SUITE_GEM,
4700 };
4701
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004702 /* The tx descriptor buffer and the TKIP space. */
4703 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4704 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004705
4706 /* unit us */
4707 /* FIXME: find a proper value */
4708 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004709 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004710
4711 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004712 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004713 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004714 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004715 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004716 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004717 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004718 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004719 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004720 IEEE80211_HW_AP_LINK_PS |
4721 IEEE80211_HW_AMPDU_AGGREGATION |
4722 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004723
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004724 wl->hw->wiphy->cipher_suites = cipher_suites;
4725 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4726
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004727 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004728 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4729 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004730 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004731 wl->hw->wiphy->max_sched_scan_ssids = 16;
4732 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004733 /*
4734 * Maximum length of elements in scanning probe request templates
4735 * should be the maximum length possible for a template, without
4736 * the IEEE80211 header of the template
4737 */
Eliad Peller154037d2011-08-14 13:17:12 +03004738 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004739 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004740
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004741 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4742 sizeof(struct ieee80211_header);
4743
Eliad Peller1ec23f72011-08-25 14:26:54 +03004744 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4745
Luciano Coelho4a31c112011-03-21 23:16:14 +02004746 /* make sure all our channels fit in the scanned_ch bitmask */
4747 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4748 ARRAY_SIZE(wl1271_channels_5ghz) >
4749 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004750 /*
4751 * We keep local copies of the band structs because we need to
4752 * modify them on a per-device basis.
4753 */
4754 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4755 sizeof(wl1271_band_2ghz));
4756 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4757 sizeof(wl1271_band_5ghz));
4758
4759 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4760 &wl->bands[IEEE80211_BAND_2GHZ];
4761 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4762 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004763
Kalle Valo12bd8942010-03-18 12:26:33 +02004764 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004765 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004766
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004767 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4768
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004769 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004770
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004771 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004772 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004773
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004774 wl->hw->max_rx_aggregation_subframes = 8;
4775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004776 return 0;
4777}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004778EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004780#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004781
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004782struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004783{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004784 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004785 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004786 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004787 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004788 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004789
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004790 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4791
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004792 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4793 if (!hw) {
4794 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004795 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004796 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004797 }
4798
Julia Lawall929ebd32010-05-15 23:16:39 +02004799 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004800 if (!plat_dev) {
4801 wl1271_error("could not allocate platform_device");
4802 ret = -ENOMEM;
4803 goto err_plat_alloc;
4804 }
4805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004806 wl = hw->priv;
4807 memset(wl, 0, sizeof(*wl));
4808
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004809 INIT_LIST_HEAD(&wl->list);
4810
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004811 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004812 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004813
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004814 for (i = 0; i < NUM_TX_QUEUES; i++)
4815 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004816
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004817 for (i = 0; i < NUM_TX_QUEUES; i++)
4818 for (j = 0; j < AP_MAX_LINKS; j++)
4819 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4820
Ido Yariva6208652011-03-01 15:14:41 +02004821 skb_queue_head_init(&wl->deferred_rx_queue);
4822 skb_queue_head_init(&wl->deferred_tx_queue);
4823
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004824 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004825 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004826 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004827 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4828 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4829 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004830 INIT_WORK(&wl->rx_streaming_enable_work,
4831 wl1271_rx_streaming_enable_work);
4832 INIT_WORK(&wl->rx_streaming_disable_work,
4833 wl1271_rx_streaming_disable_work);
4834
Eliad Peller92ef8962011-06-07 12:50:46 +03004835 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4836 if (!wl->freezable_wq) {
4837 ret = -ENOMEM;
4838 goto err_hw;
4839 }
4840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004841 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004842 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004843 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004844 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004845 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004846 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004847 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004848 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004849 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004850 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004851 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004852 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004853 wl->bss_type = MAX_BSS_TYPE;
4854 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004855 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004856 wl->ap_ps_map = 0;
4857 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004858 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004859 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004860 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004861 wl->tx_security_seq = 0;
4862 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004863 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004864 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004865 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004866 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004867 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4868 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004869 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004870 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4871 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004872 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004873 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4874 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004875 wl->fwlog_size = 0;
4876 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004877
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004878 /* The system link is always allocated */
4879 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4880
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004881 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004882 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004883 wl->tx_frames[i] = NULL;
4884
4885 spin_lock_init(&wl->wl_lock);
4886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004887 wl->state = WL1271_STATE_OFF;
4888 mutex_init(&wl->mutex);
4889
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004890 /* Apply default driver configuration. */
4891 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004892 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4893 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004894
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004895 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4896 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4897 if (!wl->aggr_buf) {
4898 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004899 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004900 }
4901
Ido Yariv990f5de2011-03-31 10:06:59 +02004902 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4903 if (!wl->dummy_packet) {
4904 ret = -ENOMEM;
4905 goto err_aggr;
4906 }
4907
Ido Yariv95dac04f2011-06-06 14:57:06 +03004908 /* Allocate one page for the FW log */
4909 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4910 if (!wl->fwlog) {
4911 ret = -ENOMEM;
4912 goto err_dummy_packet;
4913 }
4914
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004915 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004916 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004917 if (ret) {
4918 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004919 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004920 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004921 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004922
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004923 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004924 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004925 if (ret < 0) {
4926 wl1271_error("failed to create sysfs file bt_coex_state");
4927 goto err_platform;
4928 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004929
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004930 /* Create sysfs file to get HW PG version */
4931 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4932 if (ret < 0) {
4933 wl1271_error("failed to create sysfs file hw_pg_ver");
4934 goto err_bt_coex_state;
4935 }
4936
Ido Yariv95dac04f2011-06-06 14:57:06 +03004937 /* Create sysfs file for the FW log */
4938 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4939 if (ret < 0) {
4940 wl1271_error("failed to create sysfs file fwlog");
4941 goto err_hw_pg_ver;
4942 }
4943
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004944 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004945
Ido Yariv95dac04f2011-06-06 14:57:06 +03004946err_hw_pg_ver:
4947 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4948
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004949err_bt_coex_state:
4950 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4951
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004952err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004953 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004954
Ido Yariv95dac04f2011-06-06 14:57:06 +03004955err_fwlog:
4956 free_page((unsigned long)wl->fwlog);
4957
Ido Yariv990f5de2011-03-31 10:06:59 +02004958err_dummy_packet:
4959 dev_kfree_skb(wl->dummy_packet);
4960
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004961err_aggr:
4962 free_pages((unsigned long)wl->aggr_buf, order);
4963
Eliad Peller92ef8962011-06-07 12:50:46 +03004964err_wq:
4965 destroy_workqueue(wl->freezable_wq);
4966
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004967err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004968 wl1271_debugfs_exit(wl);
4969 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004970
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004971err_plat_alloc:
4972 ieee80211_free_hw(hw);
4973
4974err_hw_alloc:
4975
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004976 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004977}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004978EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004979
4980int wl1271_free_hw(struct wl1271 *wl)
4981{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004982 /* Unblock any fwlog readers */
4983 mutex_lock(&wl->mutex);
4984 wl->fwlog_size = -1;
4985 wake_up_interruptible_all(&wl->fwlog_waitq);
4986 mutex_unlock(&wl->mutex);
4987
4988 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004989
4990 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4991
4992 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004993 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004994 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004995 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004996 free_pages((unsigned long)wl->aggr_buf,
4997 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004998 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004999
5000 wl1271_debugfs_exit(wl);
5001
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005002 vfree(wl->fw);
5003 wl->fw = NULL;
5004 kfree(wl->nvs);
5005 wl->nvs = NULL;
5006
5007 kfree(wl->fw_status);
5008 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005009 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005010
5011 ieee80211_free_hw(wl->hw);
5012
5013 return 0;
5014}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005015EXPORT_SYMBOL_GPL(wl1271_free_hw);
5016
Guy Eilam491bbd62011-01-12 10:33:29 +01005017u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005018EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005019module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005020MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5021
Ido Yariv95dac04f2011-06-06 14:57:06 +03005022module_param_named(fwlog, fwlog_param, charp, 0);
5023MODULE_PARM_DESC(keymap,
5024 "FW logger options: continuous, ondemand, dbgpins or disable");
5025
Eliad Peller2a5bff02011-08-25 18:10:59 +03005026module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5027MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5028
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005029MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005030MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005031MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");