blob: 8aff8d4102d5d92baf43ee4d275a0acade82d62f [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,
242 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300243 .keep_alive_interval = 55000,
244 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200246 .itrim = {
247 .enable = false,
248 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200249 },
250 .pm_config = {
251 .host_clk_settling_time = 5000,
252 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300253 },
254 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100259 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200260 },
261 .scan = {
262 .min_dwell_time_active = 7500,
263 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100264 .min_dwell_time_passive = 100000,
265 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200266 .num_probe_reqs = 2,
267 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300268 .sched_scan = {
269 /* sched_scan requires dwell times in TU instead of TU/1000 */
270 .min_dwell_time_active = 8,
271 .max_dwell_time_active = 30,
272 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300273 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300274 .num_probe_reqs = 2,
275 .rssi_threshold = -90,
276 .snr_threshold = 0,
277 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200278 .rf = {
279 .tx_per_channel_power_compensation_2 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 },
282 .tx_per_channel_power_compensation_5 = {
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 },
287 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100288 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300289 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100290 .tx_ba_win_size = 64,
291 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300292 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100293 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200294 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200295 .num_stations = 1,
296 .ssid_profiles = 1,
297 .rx_block_num = 70,
298 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300299 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200300 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .min_req_rx_blocks = 22,
302 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 },
304 .mem_wl128x = {
305 .num_stations = 1,
306 .ssid_profiles = 1,
307 .rx_block_num = 40,
308 .tx_min_block_num = 40,
309 .dynamic_memory = 1,
310 .min_req_tx_blocks = 45,
311 .min_req_rx_blocks = 22,
312 .tx_min = 27,
313 },
Shahar Leviff868432011-04-11 15:41:46 +0300314 .fm_coex = {
315 .enable = true,
316 .swallow_period = 5,
317 .n_divider_fref_set_1 = 0xff, /* default */
318 .n_divider_fref_set_2 = 12,
319 .m_divider_fref_set_1 = 148,
320 .m_divider_fref_set_2 = 0xffff, /* default */
321 .coex_pll_stabilization_time = 0xffffffff, /* default */
322 .ldo_stabilization_time = 0xffff, /* default */
323 .fm_disturbed_band_margin = 0xff, /* default */
324 .swallow_clk_diff = 0xff, /* default */
325 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300326 .rx_streaming = {
327 .duration = 150,
328 .queues = 0x1,
329 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300330 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300331 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300332 .fwlog = {
333 .mode = WL12XX_FWLOG_ON_DEMAND,
334 .mem_blocks = 2,
335 .severity = 0,
336 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
337 .output = WL12XX_FWLOG_OUTPUT_HOST,
338 .threshold = 0,
339 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300340 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300341 .rate = {
342 .rate_retry_score = 32000,
343 .per_add = 8192,
344 .per_th1 = 2048,
345 .per_th2 = 4096,
346 .max_per = 8100,
347 .inverse_curiosity_factor = 5,
348 .tx_fail_low_th = 4,
349 .tx_fail_high_th = 10,
350 .per_alpha_shift = 4,
351 .per_add_shift = 13,
352 .per_beta1_shift = 10,
353 .per_beta2_shift = 8,
354 .rate_check_up = 2,
355 .rate_check_down = 12,
356 .rate_retry_policy = {
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00,
360 },
361 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300362};
363
Ido Yariv95dac04f2011-06-06 14:57:06 +0300364static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300365static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300366
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300367static void __wl1271_op_remove_interface(struct wl1271 *wl,
368 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200369static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200370
371
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200372static void wl1271_device_release(struct device *dev)
373{
374
375}
376
377static struct platform_device wl1271_device = {
378 .name = "wl1271",
379 .id = -1,
380
381 /* device model insists to have a release function */
382 .dev = {
383 .release = wl1271_device_release,
384 },
385};
386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300390static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
391{
392 int ret;
393 if (operstate != IF_OPER_UP)
394 return 0;
395
396 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
397 return 0;
398
Eliad Pellerb67476e2011-08-14 13:17:23 +0300399 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300400 if (ret < 0)
401 return ret;
402
Eliad Peller251c1772011-08-14 13:17:17 +0300403 wl12xx_croc(wl, wl->role_id);
404
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300405 wl1271_info("Association completed.");
406 return 0;
407}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300408static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
409 void *arg)
410{
411 struct net_device *dev = arg;
412 struct wireless_dev *wdev;
413 struct wiphy *wiphy;
414 struct ieee80211_hw *hw;
415 struct wl1271 *wl;
416 struct wl1271 *wl_temp;
417 int ret = 0;
418
419 /* Check that this notification is for us. */
420 if (what != NETDEV_CHANGE)
421 return NOTIFY_DONE;
422
423 wdev = dev->ieee80211_ptr;
424 if (wdev == NULL)
425 return NOTIFY_DONE;
426
427 wiphy = wdev->wiphy;
428 if (wiphy == NULL)
429 return NOTIFY_DONE;
430
431 hw = wiphy_priv(wiphy);
432 if (hw == NULL)
433 return NOTIFY_DONE;
434
435 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200436 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300437 list_for_each_entry(wl, &wl_list, list) {
438 if (wl == wl_temp)
439 break;
440 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200441 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300442 if (wl != wl_temp)
443 return NOTIFY_DONE;
444
445 mutex_lock(&wl->mutex);
446
447 if (wl->state == WL1271_STATE_OFF)
448 goto out;
449
450 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
451 goto out;
452
Ido Yariva6208652011-03-01 15:14:41 +0200453 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 if (ret < 0)
455 goto out;
456
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300457 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300458
459 wl1271_ps_elp_sleep(wl);
460
461out:
462 mutex_unlock(&wl->mutex);
463
464 return NOTIFY_OK;
465}
466
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100467static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200468 struct regulatory_request *request)
469{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100470 struct ieee80211_supported_band *band;
471 struct ieee80211_channel *ch;
472 int i;
473
474 band = wiphy->bands[IEEE80211_BAND_5GHZ];
475 for (i = 0; i < band->n_channels; i++) {
476 ch = &band->channels[i];
477 if (ch->flags & IEEE80211_CHAN_DISABLED)
478 continue;
479
480 if (ch->flags & IEEE80211_CHAN_RADAR)
481 ch->flags |= IEEE80211_CHAN_NO_IBSS |
482 IEEE80211_CHAN_PASSIVE_SCAN;
483
484 }
485
486 return 0;
487}
488
Eliad Peller77ddaa12011-05-15 11:10:29 +0300489static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
490{
491 int ret = 0;
492
493 /* we should hold wl->mutex */
494 ret = wl1271_acx_ps_rx_streaming(wl, enable);
495 if (ret < 0)
496 goto out;
497
498 if (enable)
499 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
500 else
501 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
502out:
503 return ret;
504}
505
506/*
507 * this function is being called when the rx_streaming interval
508 * has beed changed or rx_streaming should be disabled
509 */
510int wl1271_recalc_rx_streaming(struct wl1271 *wl)
511{
512 int ret = 0;
513 int period = wl->conf.rx_streaming.interval;
514
515 /* don't reconfigure if rx_streaming is disabled */
516 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
517 goto out;
518
519 /* reconfigure/disable according to new streaming_period */
520 if (period &&
521 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
522 (wl->conf.rx_streaming.always ||
523 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
524 ret = wl1271_set_rx_streaming(wl, true);
525 else {
526 ret = wl1271_set_rx_streaming(wl, false);
527 /* don't cancel_work_sync since we might deadlock */
528 del_timer_sync(&wl->rx_streaming_timer);
529 }
530out:
531 return ret;
532}
533
534static void wl1271_rx_streaming_enable_work(struct work_struct *work)
535{
536 int ret;
537 struct wl1271 *wl =
538 container_of(work, struct wl1271, rx_streaming_enable_work);
539
540 mutex_lock(&wl->mutex);
541
542 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
543 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
544 (!wl->conf.rx_streaming.always &&
545 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
546 goto out;
547
548 if (!wl->conf.rx_streaming.interval)
549 goto out;
550
551 ret = wl1271_ps_elp_wakeup(wl);
552 if (ret < 0)
553 goto out;
554
555 ret = wl1271_set_rx_streaming(wl, true);
556 if (ret < 0)
557 goto out_sleep;
558
559 /* stop it after some time of inactivity */
560 mod_timer(&wl->rx_streaming_timer,
561 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
562
563out_sleep:
564 wl1271_ps_elp_sleep(wl);
565out:
566 mutex_unlock(&wl->mutex);
567}
568
569static void wl1271_rx_streaming_disable_work(struct work_struct *work)
570{
571 int ret;
572 struct wl1271 *wl =
573 container_of(work, struct wl1271, rx_streaming_disable_work);
574
575 mutex_lock(&wl->mutex);
576
577 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
578 goto out;
579
580 ret = wl1271_ps_elp_wakeup(wl);
581 if (ret < 0)
582 goto out;
583
584 ret = wl1271_set_rx_streaming(wl, false);
585 if (ret)
586 goto out_sleep;
587
588out_sleep:
589 wl1271_ps_elp_sleep(wl);
590out:
591 mutex_unlock(&wl->mutex);
592}
593
594static void wl1271_rx_streaming_timer(unsigned long data)
595{
596 struct wl1271 *wl = (struct wl1271 *)data;
597 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
598}
599
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300600static void wl1271_conf_init(struct wl1271 *wl)
601{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300602
603 /*
604 * This function applies the default configuration to the driver. This
605 * function is invoked upon driver load (spi probe.)
606 *
607 * The configuration is stored in a run-time structure in order to
608 * facilitate for run-time adjustment of any of the parameters. Making
609 * changes to the configuration structure will apply the new values on
610 * the next interface up (wl1271_op_start.)
611 */
612
613 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300614 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300615
Ido Yariv95dac04f2011-06-06 14:57:06 +0300616 /* Adjust settings according to optional module parameters */
617 if (fwlog_param) {
618 if (!strcmp(fwlog_param, "continuous")) {
619 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
620 } else if (!strcmp(fwlog_param, "ondemand")) {
621 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
622 } else if (!strcmp(fwlog_param, "dbgpins")) {
623 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
624 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
625 } else if (!strcmp(fwlog_param, "disable")) {
626 wl->conf.fwlog.mem_blocks = 0;
627 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
628 } else {
629 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
630 }
631 }
632}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634static int wl1271_plt_init(struct wl1271 *wl)
635{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200636 struct conf_tx_ac_category *conf_ac;
637 struct conf_tx_tid *conf_tid;
638 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639
Shahar Levi49d750ca2011-03-06 16:32:09 +0200640 if (wl->chip.id == CHIP_ID_1283_PG20)
641 ret = wl128x_cmd_general_parms(wl);
642 else
643 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200644 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200645 return ret;
646
Shahar Levi49d750ca2011-03-06 16:32:09 +0200647 if (wl->chip.id == CHIP_ID_1283_PG20)
648 ret = wl128x_cmd_radio_parms(wl);
649 else
650 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200651 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200652 return ret;
653
Shahar Levi49d750ca2011-03-06 16:32:09 +0200654 if (wl->chip.id != CHIP_ID_1283_PG20) {
655 ret = wl1271_cmd_ext_radio_parms(wl);
656 if (ret < 0)
657 return ret;
658 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200659 if (ret < 0)
660 return ret;
661
Shahar Levi48a61472011-03-06 16:32:08 +0200662 /* Chip-specific initializations */
663 ret = wl1271_chip_specific_init(wl);
664 if (ret < 0)
665 return ret;
666
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200667 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200668 if (ret < 0)
669 return ret;
670
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 ret = wl1271_acx_init_mem_config(wl);
672 if (ret < 0)
673 return ret;
674
Luciano Coelho12419cce2010-02-18 13:25:44 +0200675 /* PHY layer config */
676 ret = wl1271_init_phy_config(wl);
677 if (ret < 0)
678 goto out_free_memmap;
679
680 ret = wl1271_acx_dco_itrim_params(wl);
681 if (ret < 0)
682 goto out_free_memmap;
683
684 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200685 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200686 if (ret < 0)
687 goto out_free_memmap;
688
689 /* Bluetooth WLAN coexistence */
690 ret = wl1271_init_pta(wl);
691 if (ret < 0)
692 goto out_free_memmap;
693
Shahar Leviff868432011-04-11 15:41:46 +0300694 /* FM WLAN coexistence */
695 ret = wl1271_acx_fm_coex(wl);
696 if (ret < 0)
697 goto out_free_memmap;
698
Luciano Coelho12419cce2010-02-18 13:25:44 +0200699 /* Energy detection */
700 ret = wl1271_init_energy_detection(wl);
701 if (ret < 0)
702 goto out_free_memmap;
703
Eliad Peller7f0979882011-08-14 13:17:06 +0300704 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600705 if (ret < 0)
706 goto out_free_memmap;
707
Luciano Coelho12419cce2010-02-18 13:25:44 +0200708 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100709 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200710 if (ret < 0)
711 goto out_free_memmap;
712
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200713 /* Default TID/AC configuration */
714 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200715 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200716 conf_ac = &wl->conf.tx.ac_conf[i];
717 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
718 conf_ac->cw_max, conf_ac->aifsn,
719 conf_ac->tx_op_limit);
720 if (ret < 0)
721 goto out_free_memmap;
722
Luciano Coelho12419cce2010-02-18 13:25:44 +0200723 conf_tid = &wl->conf.tx.tid_conf[i];
724 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
725 conf_tid->channel_type,
726 conf_tid->tsid,
727 conf_tid->ps_scheme,
728 conf_tid->ack_policy,
729 conf_tid->apsd_conf[0],
730 conf_tid->apsd_conf[1]);
731 if (ret < 0)
732 goto out_free_memmap;
733 }
734
Luciano Coelho12419cce2010-02-18 13:25:44 +0200735 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200736 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200738 goto out_free_memmap;
739
740 /* Configure for CAM power saving (ie. always active) */
741 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
742 if (ret < 0)
743 goto out_free_memmap;
744
745 /* configure PM */
746 ret = wl1271_acx_pm_config(wl);
747 if (ret < 0)
748 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749
750 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200751
752 out_free_memmap:
753 kfree(wl->target_mem_map);
754 wl->target_mem_map = NULL;
755
756 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757}
758
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300759static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200760{
761 bool fw_ps;
762
763 /* only regulate station links */
764 if (hlid < WL1271_AP_STA_HLID_START)
765 return;
766
767 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
768
769 /*
770 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300771 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300773 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774 wl1271_ps_link_end(wl, hlid);
775
776 /* Start high-level PS if the STA is asleep with enough blocks in FW */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300777 else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200778 wl1271_ps_link_start(wl, hlid, true);
779}
780
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300781bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
782{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300783 int id;
784
785 /* global/broadcast "stations" are always active */
786 if (hlid < WL1271_AP_STA_HLID_START)
787 return true;
788
789 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300790 return test_bit(id, wl->ap_hlid_map);
791}
792
793static void wl12xx_irq_update_links_status(struct wl1271 *wl,
794 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200795{
796 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300797 u8 hlid, cnt;
798
799 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200800
801 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
802 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
803 wl1271_debug(DEBUG_PSM,
804 "link ps prev 0x%x cur 0x%x changed 0x%x",
805 wl->ap_fw_ps_map, cur_fw_ps_map,
806 wl->ap_fw_ps_map ^ cur_fw_ps_map);
807
808 wl->ap_fw_ps_map = cur_fw_ps_map;
809 }
810
811 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300812 if (!wl1271_is_active_sta(wl, hlid))
813 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200814
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300815 cnt = status->tx_lnk_free_pkts[hlid] -
816 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300818 wl->links[hlid].prev_freed_pkts =
819 status->tx_lnk_free_pkts[hlid];
820 wl->links[hlid].allocated_pkts -= cnt;
821
822 wl12xx_irq_ps_regulate_link(wl, hlid,
823 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200824 }
825}
826
Eliad Peller4d56ad92011-08-14 13:17:05 +0300827static void wl12xx_fw_status(struct wl1271 *wl,
828 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200830 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200831 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300832 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300833 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
838 "drv_rx_counter = %d, tx_results_counter = %d)",
839 status->intr,
840 status->fw_rx_counter,
841 status->drv_rx_counter,
842 status->tx_results_counter);
843
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300844 for (i = 0; i < NUM_TX_QUEUES; i++) {
845 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300846 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300847 (status->tx_released_pkts[i] -
848 wl->tx_pkts_freed[i]) & 0xff;
849
850 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
851 }
852
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300853 /* prevent wrap-around in total blocks counter */
854 if (likely(wl->tx_blocks_freed <=
855 le32_to_cpu(status->total_released_blks)))
856 freed_blocks = le32_to_cpu(status->total_released_blks) -
857 wl->tx_blocks_freed;
858 else
859 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
860 le32_to_cpu(status->total_released_blks);
861
Eliad Peller4d56ad92011-08-14 13:17:05 +0300862 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200863
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300864 wl->tx_allocated_blocks -= freed_blocks;
865
Eliad Peller4d56ad92011-08-14 13:17:05 +0300866 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 /*
869 * The FW might change the total number of TX memblocks before
870 * we get a notification about blocks being released. Thus, the
871 * available blocks calculation might yield a temporary result
872 * which is lower than the actual available blocks. Keeping in
873 * mind that only blocks that were allocated can be moved from
874 * TX to RX, tx_blocks_available should never decrease here.
875 */
876 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
877 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariva5225502010-10-12 14:49:10 +0200879 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200880 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200881 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300884 if (wl->bss_type == BSS_TYPE_AP_BSS)
885 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200888 getnstimeofday(&ts);
889 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
890 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891}
892
Ido Yariva6208652011-03-01 15:14:41 +0200893static void wl1271_flush_deferred_work(struct wl1271 *wl)
894{
895 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200896
Ido Yariva6208652011-03-01 15:14:41 +0200897 /* Pass all received frames to the network stack */
898 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
899 ieee80211_rx_ni(wl->hw, skb);
900
901 /* Return sent skbs to the network stack */
902 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300903 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200904}
905
906static void wl1271_netstack_work(struct work_struct *work)
907{
908 struct wl1271 *wl =
909 container_of(work, struct wl1271, netstack_work);
910
911 do {
912 wl1271_flush_deferred_work(wl);
913 } while (skb_queue_len(&wl->deferred_rx_queue));
914}
915
916#define WL1271_IRQ_MAX_LOOPS 256
917
918irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300921 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200922 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200923 struct wl1271 *wl = (struct wl1271 *)cookie;
924 bool done = false;
925 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200926 unsigned long flags;
927
928 /* TX might be handled here, avoid redundant work */
929 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
930 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931
Ido Yariv341b7cd2011-03-31 10:07:01 +0200932 /*
933 * In case edge triggered interrupt must be used, we cannot iterate
934 * more than once without introducing race conditions with the hardirq.
935 */
936 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
937 loopcount = 1;
938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 mutex_lock(&wl->mutex);
940
941 wl1271_debug(DEBUG_IRQ, "IRQ work");
942
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200943 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 goto out;
945
Ido Yariva6208652011-03-01 15:14:41 +0200946 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 if (ret < 0)
948 goto out;
949
Ido Yariva6208652011-03-01 15:14:41 +0200950 while (!done && loopcount--) {
951 /*
952 * In order to avoid a race with the hardirq, clear the flag
953 * before acknowledging the chip. Since the mutex is held,
954 * wl1271_ps_elp_wakeup cannot be called concurrently.
955 */
956 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
957 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200958
Eliad Peller4d56ad92011-08-14 13:17:05 +0300959 wl12xx_fw_status(wl, wl->fw_status);
960 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200961 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200962 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200963 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200964 continue;
965 }
966
Eliad Pellerccc83b02010-10-27 14:09:57 +0200967 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
968 wl1271_error("watchdog interrupt received! "
969 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300970 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200971
972 /* restarting the chip. ignore any other interrupt. */
973 goto out;
974 }
975
Ido Yariva6208652011-03-01 15:14:41 +0200976 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200977 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
978
Eliad Peller4d56ad92011-08-14 13:17:05 +0300979 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200980
Ido Yariva5225502010-10-12 14:49:10 +0200981 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200982 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200983 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300984 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200985 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200986 /*
987 * In order to avoid starvation of the TX path,
988 * call the work function directly.
989 */
990 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200991 } else {
992 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200993 }
994
Ido Yariv8aad2462011-03-01 15:14:38 +0200995 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300996 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200997 (wl->tx_results_count & 0xff))
998 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200999
1000 /* Make sure the deferred queues don't get too long */
1001 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1002 skb_queue_len(&wl->deferred_rx_queue);
1003 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1004 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001005 }
1006
1007 if (intr & WL1271_ACX_INTR_EVENT_A) {
1008 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1009 wl1271_event_handle(wl, 0);
1010 }
1011
1012 if (intr & WL1271_ACX_INTR_EVENT_B) {
1013 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1014 wl1271_event_handle(wl, 1);
1015 }
1016
1017 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1018 wl1271_debug(DEBUG_IRQ,
1019 "WL1271_ACX_INTR_INIT_COMPLETE");
1020
1021 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1022 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 }
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 wl1271_ps_elp_sleep(wl);
1026
1027out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001028 spin_lock_irqsave(&wl->wl_lock, flags);
1029 /* In case TX was not handled here, queue TX work */
1030 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1031 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001032 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001033 ieee80211_queue_work(wl->hw, &wl->tx_work);
1034 spin_unlock_irqrestore(&wl->wl_lock, flags);
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001037
1038 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039}
Ido Yariva6208652011-03-01 15:14:41 +02001040EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042static int wl1271_fetch_firmware(struct wl1271 *wl)
1043{
1044 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret;
1047
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001048 if (wl->chip.id == CHIP_ID_1283_PG20)
1049 fw_name = WL128X_FW_NAME;
1050 else
1051 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001052
1053 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1054
1055 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (ret < 0) {
1058 wl1271_error("could not get firmware: %d", ret);
1059 return ret;
1060 }
1061
1062 if (fw->size % 4) {
1063 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1064 fw->size);
1065 ret = -EILSEQ;
1066 goto out;
1067 }
1068
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001071 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 if (!wl->fw) {
1074 wl1271_error("could not allocate memory for the firmware");
1075 ret = -ENOMEM;
1076 goto out;
1077 }
1078
1079 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = 0;
1081
1082out:
1083 release_firmware(fw);
1084
1085 return ret;
1086}
1087
1088static int wl1271_fetch_nvs(struct wl1271 *wl)
1089{
1090 const struct firmware *fw;
1091 int ret;
1092
Shahar Levi5aa42342011-03-06 16:32:07 +02001093 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 if (ret < 0) {
1096 wl1271_error("could not get nvs file: %d", ret);
1097 return ret;
1098 }
1099
Shahar Levibc765bf2011-03-06 16:32:10 +02001100 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
1102 if (!wl->nvs) {
1103 wl1271_error("could not allocate memory for the nvs file");
1104 ret = -ENOMEM;
1105 goto out;
1106 }
1107
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001108 wl->nvs_len = fw->size;
1109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110out:
1111 release_firmware(fw);
1112
1113 return ret;
1114}
1115
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001116void wl12xx_queue_recovery_work(struct wl1271 *wl)
1117{
1118 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1119 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1120}
1121
Ido Yariv95dac04f2011-06-06 14:57:06 +03001122size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1123{
1124 size_t len = 0;
1125
1126 /* The FW log is a length-value list, find where the log end */
1127 while (len < maxlen) {
1128 if (memblock[len] == 0)
1129 break;
1130 if (len + memblock[len] + 1 > maxlen)
1131 break;
1132 len += memblock[len] + 1;
1133 }
1134
1135 /* Make sure we have enough room */
1136 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1137
1138 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1139 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1140 wl->fwlog_size += len;
1141
1142 return len;
1143}
1144
1145static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1146{
1147 u32 addr;
1148 u32 first_addr;
1149 u8 *block;
1150
1151 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1152 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1153 (wl->conf.fwlog.mem_blocks == 0))
1154 return;
1155
1156 wl1271_info("Reading FW panic log");
1157
1158 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1159 if (!block)
1160 return;
1161
1162 /*
1163 * Make sure the chip is awake and the logger isn't active.
1164 * This might fail if the firmware hanged.
1165 */
1166 if (!wl1271_ps_elp_wakeup(wl))
1167 wl12xx_cmd_stop_fwlog(wl);
1168
1169 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001170 wl12xx_fw_status(wl, wl->fw_status);
1171 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001172 if (!first_addr)
1173 goto out;
1174
1175 /* Traverse the memory blocks linked list */
1176 addr = first_addr;
1177 do {
1178 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1179 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1180 false);
1181
1182 /*
1183 * Memory blocks are linked to one another. The first 4 bytes
1184 * of each memory block hold the hardware address of the next
1185 * one. The last memory block points to the first one.
1186 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001188 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1189 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1190 break;
1191 } while (addr && (addr != first_addr));
1192
1193 wake_up_interruptible(&wl->fwlog_waitq);
1194
1195out:
1196 kfree(block);
1197}
1198
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199static void wl1271_recovery_work(struct work_struct *work)
1200{
1201 struct wl1271 *wl =
1202 container_of(work, struct wl1271, recovery_work);
1203
1204 mutex_lock(&wl->mutex);
1205
1206 if (wl->state != WL1271_STATE_ON)
1207 goto out;
1208
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001209 /* Avoid a recursive recovery */
1210 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1211
Ido Yariv95dac04f2011-06-06 14:57:06 +03001212 wl12xx_read_fwlog_panic(wl);
1213
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001214 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1215 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216
Eliad Peller2a5bff02011-08-25 18:10:59 +03001217 BUG_ON(bug_on_recovery);
1218
Oz Krakowskib992c682011-06-26 10:36:02 +03001219 /*
1220 * Advance security sequence number to overcome potential progress
1221 * in the firmware during recovery. This doens't hurt if the network is
1222 * not encrypted.
1223 */
1224 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1225 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1226 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1227
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001228 /* Prevent spurious TX during FW restart */
1229 ieee80211_stop_queues(wl->hw);
1230
Luciano Coelho33c2c062011-05-10 14:46:02 +03001231 if (wl->sched_scanning) {
1232 ieee80211_sched_scan_stopped(wl->hw);
1233 wl->sched_scanning = false;
1234 }
1235
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001236 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001237 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001238
1239 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1240
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241 ieee80211_restart_hw(wl->hw);
1242
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001243 /*
1244 * Its safe to enable TX now - the queues are stopped after a request
1245 * to restart the HW.
1246 */
1247 ieee80211_wake_queues(wl->hw);
1248
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001249out:
1250 mutex_unlock(&wl->mutex);
1251}
1252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253static void wl1271_fw_wakeup(struct wl1271 *wl)
1254{
1255 u32 elp_reg;
1256
1257 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001258 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259}
1260
1261static int wl1271_setup(struct wl1271 *wl)
1262{
1263 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1264 if (!wl->fw_status)
1265 return -ENOMEM;
1266
1267 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1268 if (!wl->tx_res_if) {
1269 kfree(wl->fw_status);
1270 return -ENOMEM;
1271 }
1272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 return 0;
1274}
1275
1276static int wl1271_chip_wakeup(struct wl1271 *wl)
1277{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001278 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 int ret = 0;
1280
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001281 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001282 ret = wl1271_power_on(wl);
1283 if (ret < 0)
1284 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001286 wl1271_io_reset(wl);
1287 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288
1289 /* We don't need a real memory partition here, because we only want
1290 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001291 memset(&partition, 0, sizeof(partition));
1292 partition.reg.start = REGISTERS_BASE;
1293 partition.reg.size = REGISTERS_DOWN_SIZE;
1294 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295
1296 /* ELP module wake up */
1297 wl1271_fw_wakeup(wl);
1298
1299 /* whal_FwCtrl_BootSm() */
1300
1301 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001302 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303
1304 /* 1. check if chip id is valid */
1305
1306 switch (wl->chip.id) {
1307 case CHIP_ID_1271_PG10:
1308 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1309 wl->chip.id);
1310
1311 ret = wl1271_setup(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 break;
1315 case CHIP_ID_1271_PG20:
1316 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1317 wl->chip.id);
1318
Shahar Levi0c005042011-06-12 10:34:43 +03001319 /*
1320 * 'end-of-transaction flag' and 'LPD mode flag'
1321 * should be set in wl127x AP mode only
1322 */
Shahar Levi564f5952011-04-04 10:20:39 +03001323 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001324 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1325 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 ret = wl1271_setup(wl);
1328 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001331 case CHIP_ID_1283_PG20:
1332 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1333 wl->chip.id);
1334
1335 ret = wl1271_setup(wl);
1336 if (ret < 0)
1337 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001338
Ido Yariv0da13da2011-03-31 10:06:58 +02001339 if (wl1271_set_block_size(wl))
1340 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001341 break;
1342 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001346 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 }
1348
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001349 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 ret = wl1271_fetch_firmware(wl);
1351 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 }
1354
1355 /* No NVS from netlink, try to get it from the filesystem */
1356 if (wl->nvs == NULL) {
1357 ret = wl1271_fetch_nvs(wl);
1358 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 }
1361
1362out:
1363 return ret;
1364}
1365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366int wl1271_plt_start(struct wl1271 *wl)
1367{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001369 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 int ret;
1371
1372 mutex_lock(&wl->mutex);
1373
1374 wl1271_notice("power up");
1375
1376 if (wl->state != WL1271_STATE_OFF) {
1377 wl1271_error("cannot go into PLT state because not "
1378 "in off state: %d", wl->state);
1379 ret = -EBUSY;
1380 goto out;
1381 }
1382
Arik Nemtsov166d5042010-10-16 21:44:57 +02001383 wl->bss_type = BSS_TYPE_STA_BSS;
1384
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 while (retries) {
1386 retries--;
1387 ret = wl1271_chip_wakeup(wl);
1388 if (ret < 0)
1389 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391 ret = wl1271_boot(wl);
1392 if (ret < 0)
1393 goto power_off;
1394
1395 ret = wl1271_plt_init(wl);
1396 if (ret < 0)
1397 goto irq_disable;
1398
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001399 wl->state = WL1271_STATE_PLT;
1400 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001401 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001402
Gery Kahn6f07b722011-07-18 14:21:49 +03001403 /* update hw/fw version info in wiphy struct */
1404 wiphy->hw_version = wl->chip.id;
1405 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1406 sizeof(wiphy->fw_version));
1407
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408 goto out;
1409
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001410irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 mutex_unlock(&wl->mutex);
1412 /* Unlocking the mutex in the middle of handling is
1413 inherently unsafe. In this case we deem it safe to do,
1414 because we need to let any possibly pending IRQ out of
1415 the system (and while we are WL1271_STATE_OFF the IRQ
1416 work function will not do anything.) Also, any other
1417 possible concurrent operations will fail due to the
1418 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001419 wl1271_disable_interrupts(wl);
1420 wl1271_flush_deferred_work(wl);
1421 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422 mutex_lock(&wl->mutex);
1423power_off:
1424 wl1271_power_off(wl);
1425 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001427 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1428 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429out:
1430 mutex_unlock(&wl->mutex);
1431
1432 return ret;
1433}
1434
Luciano Coelho4623ec72011-03-21 19:26:41 +02001435static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436{
1437 int ret = 0;
1438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 wl1271_notice("power down");
1440
1441 if (wl->state != WL1271_STATE_PLT) {
1442 wl1271_error("cannot power down because not in PLT "
1443 "state: %d", wl->state);
1444 ret = -EBUSY;
1445 goto out;
1446 }
1447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448 wl1271_power_off(wl);
1449
1450 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001451 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001454 wl1271_disable_interrupts(wl);
1455 wl1271_flush_deferred_work(wl);
1456 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001457 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001458 mutex_lock(&wl->mutex);
1459out:
1460 return ret;
1461}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001462
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001463int wl1271_plt_stop(struct wl1271 *wl)
1464{
1465 int ret;
1466
1467 mutex_lock(&wl->mutex);
1468 ret = __wl1271_plt_stop(wl);
1469 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 return ret;
1471}
1472
Johannes Berg7bb45682011-02-24 14:42:06 +01001473static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474{
1475 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001476 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001477 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001478 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001480 mapping = skb_get_queue_mapping(skb);
1481 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001482
1483 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001484 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001485
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001486 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001487
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001488 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001489 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001490 if (!wl1271_is_active_sta(wl, hlid)) {
1491 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1492 hlid, q);
1493 dev_kfree_skb(skb);
1494 goto out;
1495 }
1496
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001497 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1498 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1499 } else {
1500 skb_queue_tail(&wl->tx_queue[q], skb);
1501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001503 wl->tx_queue_count[q]++;
1504
1505 /*
1506 * The workqueue is slow to process the tx_queue and we need stop
1507 * the queue here, otherwise the queue will get too long.
1508 */
1509 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1510 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1511 ieee80211_stop_queue(wl->hw, mapping);
1512 set_bit(q, &wl->stopped_queues_map);
1513 }
1514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 /*
1516 * The chip specific setup must run before the first TX packet -
1517 * before that, the tx_work will not be initialized!
1518 */
1519
Ido Yarivb07d4032011-03-01 15:14:43 +02001520 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1521 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001522 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001523
Arik Nemtsov04216da2011-08-14 13:17:38 +03001524out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001525 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526}
1527
Shahar Leviae47c452011-03-06 16:32:14 +02001528int wl1271_tx_dummy_packet(struct wl1271 *wl)
1529{
Ido Yariv990f5de2011-03-31 10:06:59 +02001530 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001531 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001532
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 spin_lock_irqsave(&wl->wl_lock, flags);
1534 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001535 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001536 spin_unlock_irqrestore(&wl->wl_lock, flags);
1537
1538 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1539 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1540 wl1271_tx_work_locked(wl);
1541
1542 /*
1543 * If the FW TX is busy, TX work will be scheduled by the threaded
1544 * interrupt handler function
1545 */
1546 return 0;
1547}
1548
1549/*
1550 * The size of the dummy packet should be at least 1400 bytes. However, in
1551 * order to minimize the number of bus transactions, aligning it to 512 bytes
1552 * boundaries could be beneficial, performance wise
1553 */
1554#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1555
Luciano Coelhocf27d862011-04-01 21:08:23 +03001556static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001557{
1558 struct sk_buff *skb;
1559 struct ieee80211_hdr_3addr *hdr;
1560 unsigned int dummy_packet_size;
1561
1562 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1563 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1564
1565 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001566 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001567 wl1271_warning("Failed to allocate a dummy packet skb");
1568 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001569 }
1570
1571 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1572
1573 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1574 memset(hdr, 0, sizeof(*hdr));
1575 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 IEEE80211_STYPE_NULLFUNC |
1577 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001578
Ido Yariv990f5de2011-03-31 10:06:59 +02001579 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001580
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001581 /* Dummy packets require the TID to be management */
1582 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001583
1584 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001585 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001586 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001589}
1590
Ido Yariv990f5de2011-03-31 10:06:59 +02001591
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001592static struct notifier_block wl1271_dev_notifier = {
1593 .notifier_call = wl1271_dev_notify,
1594};
1595
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001596#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001597static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001598{
Eliad Pellere85d1622011-06-27 13:06:43 +03001599 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001600
Eliad Peller94390642011-05-13 11:57:13 +03001601 mutex_lock(&wl->mutex);
1602
Eliad Pellere85d1622011-06-27 13:06:43 +03001603 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1604 goto out_unlock;
1605
Eliad Peller94390642011-05-13 11:57:13 +03001606 ret = wl1271_ps_elp_wakeup(wl);
1607 if (ret < 0)
1608 goto out_unlock;
1609
1610 /* enter psm if needed*/
1611 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1612 DECLARE_COMPLETION_ONSTACK(compl);
1613
1614 wl->ps_compl = &compl;
1615 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1616 wl->basic_rate, true);
1617 if (ret < 0)
1618 goto out_sleep;
1619
1620 /* we must unlock here so we will be able to get events */
1621 wl1271_ps_elp_sleep(wl);
1622 mutex_unlock(&wl->mutex);
1623
1624 ret = wait_for_completion_timeout(
1625 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1626 if (ret <= 0) {
1627 wl1271_warning("couldn't enter ps mode!");
1628 ret = -EBUSY;
1629 goto out;
1630 }
1631
1632 /* take mutex again, and wakeup */
1633 mutex_lock(&wl->mutex);
1634
1635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
1637 goto out_unlock;
1638 }
1639out_sleep:
1640 wl1271_ps_elp_sleep(wl);
1641out_unlock:
1642 mutex_unlock(&wl->mutex);
1643out:
1644 return ret;
1645
1646}
1647
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001648static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001649{
Eliad Pellere85d1622011-06-27 13:06:43 +03001650 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001651
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001652 mutex_lock(&wl->mutex);
1653
Eliad Pellere85d1622011-06-27 13:06:43 +03001654 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1655 goto out_unlock;
1656
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001657 ret = wl1271_ps_elp_wakeup(wl);
1658 if (ret < 0)
1659 goto out_unlock;
1660
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001661 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001662
1663 wl1271_ps_elp_sleep(wl);
1664out_unlock:
1665 mutex_unlock(&wl->mutex);
1666 return ret;
1667
1668}
1669
1670static int wl1271_configure_suspend(struct wl1271 *wl)
1671{
1672 if (wl->bss_type == BSS_TYPE_STA_BSS)
1673 return wl1271_configure_suspend_sta(wl);
1674 if (wl->bss_type == BSS_TYPE_AP_BSS)
1675 return wl1271_configure_suspend_ap(wl);
1676 return 0;
1677}
1678
1679static void wl1271_configure_resume(struct wl1271 *wl)
1680{
1681 int ret;
1682 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1683 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1684
1685 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001686 return;
1687
1688 mutex_lock(&wl->mutex);
1689 ret = wl1271_ps_elp_wakeup(wl);
1690 if (ret < 0)
1691 goto out;
1692
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693 if (is_sta) {
1694 /* exit psm if it wasn't configured */
1695 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1696 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1697 wl->basic_rate, true);
1698 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001699 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001700 }
Eliad Peller94390642011-05-13 11:57:13 +03001701
1702 wl1271_ps_elp_sleep(wl);
1703out:
1704 mutex_unlock(&wl->mutex);
1705}
1706
Eliad Peller402e48612011-05-13 11:57:09 +03001707static int wl1271_op_suspend(struct ieee80211_hw *hw,
1708 struct cfg80211_wowlan *wow)
1709{
1710 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001711 int ret;
1712
Eliad Peller402e48612011-05-13 11:57:09 +03001713 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001714 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001715
Eliad Peller4a859df2011-06-06 12:21:52 +03001716 wl->wow_enabled = true;
1717 ret = wl1271_configure_suspend(wl);
1718 if (ret < 0) {
1719 wl1271_warning("couldn't prepare device to suspend");
1720 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001721 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001722 /* flush any remaining work */
1723 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001724
1725 /*
1726 * disable and re-enable interrupts in order to flush
1727 * the threaded_irq
1728 */
1729 wl1271_disable_interrupts(wl);
1730
1731 /*
1732 * set suspended flag to avoid triggering a new threaded_irq
1733 * work. no need for spinlock as interrupts are disabled.
1734 */
1735 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1736
1737 wl1271_enable_interrupts(wl);
1738 flush_work(&wl->tx_work);
1739 flush_delayed_work(&wl->pspoll_work);
1740 flush_delayed_work(&wl->elp_work);
1741
Eliad Peller402e48612011-05-13 11:57:09 +03001742 return 0;
1743}
1744
1745static int wl1271_op_resume(struct ieee80211_hw *hw)
1746{
1747 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001748 unsigned long flags;
1749 bool run_irq_work = false;
1750
Eliad Peller402e48612011-05-13 11:57:09 +03001751 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1752 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001753 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001754
1755 /*
1756 * re-enable irq_work enqueuing, and call irq_work directly if
1757 * there is a pending work.
1758 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001759 spin_lock_irqsave(&wl->wl_lock, flags);
1760 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1761 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1762 run_irq_work = true;
1763 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001764
Eliad Peller4a859df2011-06-06 12:21:52 +03001765 if (run_irq_work) {
1766 wl1271_debug(DEBUG_MAC80211,
1767 "run postponed irq_work directly");
1768 wl1271_irq(0, wl);
1769 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001770 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001772 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001773
Eliad Peller402e48612011-05-13 11:57:09 +03001774 return 0;
1775}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001776#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001778static int wl1271_op_start(struct ieee80211_hw *hw)
1779{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001780 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1781
1782 /*
1783 * We have to delay the booting of the hardware because
1784 * we need to know the local MAC address before downloading and
1785 * initializing the firmware. The MAC address cannot be changed
1786 * after boot, and without the proper MAC address, the firmware
1787 * will not function properly.
1788 *
1789 * The MAC address is first known when the corresponding interface
1790 * is added. That is where we will initialize the hardware.
1791 */
1792
1793 return 0;
1794}
1795
1796static void wl1271_op_stop(struct ieee80211_hw *hw)
1797{
1798 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1799}
1800
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001801static u8 wl12xx_get_role_type(struct wl1271 *wl)
1802{
1803 switch (wl->bss_type) {
1804 case BSS_TYPE_AP_BSS:
1805 return WL1271_ROLE_AP;
1806
1807 case BSS_TYPE_STA_BSS:
1808 return WL1271_ROLE_STA;
1809
Eliad Peller227e81e2011-08-14 13:17:26 +03001810 case BSS_TYPE_IBSS:
1811 return WL1271_ROLE_IBSS;
1812
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001813 default:
1814 wl1271_error("invalid bss_type: %d", wl->bss_type);
1815 }
1816 return WL12XX_INVALID_ROLE_TYPE;
1817}
1818
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001819static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1820 struct ieee80211_vif *vif)
1821{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001823 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001824 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001826 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001827 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001829 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1830 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831
1832 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001833 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001834 wl1271_debug(DEBUG_MAC80211,
1835 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001836 ret = -EBUSY;
1837 goto out;
1838 }
1839
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001840 /*
1841 * in some very corner case HW recovery scenarios its possible to
1842 * get here before __wl1271_op_remove_interface is complete, so
1843 * opt out if that is the case.
1844 */
1845 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1846 ret = -EBUSY;
1847 goto out;
1848 }
1849
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001850 switch (vif->type) {
1851 case NL80211_IFTYPE_STATION:
1852 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001853 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001854 break;
1855 case NL80211_IFTYPE_ADHOC:
1856 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001857 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001858 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001859 case NL80211_IFTYPE_AP:
1860 wl->bss_type = BSS_TYPE_AP_BSS;
1861 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001862 default:
1863 ret = -EOPNOTSUPP;
1864 goto out;
1865 }
1866
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001867 role_type = wl12xx_get_role_type(wl);
1868 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1869 ret = -EINVAL;
1870 goto out;
1871 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001872 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873
1874 if (wl->state != WL1271_STATE_OFF) {
1875 wl1271_error("cannot start because not in off state: %d",
1876 wl->state);
1877 ret = -EBUSY;
1878 goto out;
1879 }
1880
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001881 while (retries) {
1882 retries--;
1883 ret = wl1271_chip_wakeup(wl);
1884 if (ret < 0)
1885 goto power_off;
1886
1887 ret = wl1271_boot(wl);
1888 if (ret < 0)
1889 goto power_off;
1890
Eliad Peller227e81e2011-08-14 13:17:26 +03001891 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1892 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001893 /*
1894 * The device role is a special role used for
1895 * rx and tx frames prior to association (as
1896 * the STA role can get packets only from
1897 * its associated bssid)
1898 */
1899 ret = wl12xx_cmd_role_enable(wl,
1900 WL1271_ROLE_DEVICE,
1901 &wl->dev_role_id);
1902 if (ret < 0)
1903 goto irq_disable;
1904 }
1905
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1907 if (ret < 0)
1908 goto irq_disable;
1909
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001910 ret = wl1271_hw_init(wl);
1911 if (ret < 0)
1912 goto irq_disable;
1913
Eliad Peller71125ab2010-10-28 21:46:43 +02001914 booted = true;
1915 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001917irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001918 mutex_unlock(&wl->mutex);
1919 /* Unlocking the mutex in the middle of handling is
1920 inherently unsafe. In this case we deem it safe to do,
1921 because we need to let any possibly pending IRQ out of
1922 the system (and while we are WL1271_STATE_OFF the IRQ
1923 work function will not do anything.) Also, any other
1924 possible concurrent operations will fail due to the
1925 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001926 wl1271_disable_interrupts(wl);
1927 wl1271_flush_deferred_work(wl);
1928 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001929 mutex_lock(&wl->mutex);
1930power_off:
1931 wl1271_power_off(wl);
1932 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001933
Eliad Peller71125ab2010-10-28 21:46:43 +02001934 if (!booted) {
1935 wl1271_error("firmware boot failed despite %d retries",
1936 WL1271_BOOT_RETRIES);
1937 goto out;
1938 }
1939
1940 wl->vif = vif;
1941 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001942 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001943 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001944
1945 /* update hw/fw version info in wiphy struct */
1946 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001947 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001948 sizeof(wiphy->fw_version));
1949
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001950 /*
1951 * Now we know if 11a is supported (info from the NVS), so disable
1952 * 11a channels if not supported
1953 */
1954 if (!wl->enable_11a)
1955 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1956
1957 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1958 wl->enable_11a ? "" : "not ");
1959
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001960out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 mutex_unlock(&wl->mutex);
1962
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001963 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001964 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001965 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001966 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 return ret;
1969}
1970
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001971static void __wl1271_op_remove_interface(struct wl1271 *wl,
1972 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001974 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001976 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001978 /* because of hardware recovery, we may get here twice */
1979 if (wl->state != WL1271_STATE_ON)
1980 return;
1981
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001982 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001984 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001985 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001986 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001987
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001988 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001989 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001990 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001991
Luciano Coelho08688d62010-07-08 17:50:07 +03001992 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001993 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001994 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001995 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001996 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 }
1998
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001999 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2000 /* disable active roles */
2001 ret = wl1271_ps_elp_wakeup(wl);
2002 if (ret < 0)
2003 goto deinit;
2004
Eliad Peller04e80792011-08-14 13:17:09 +03002005 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2006 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2007 if (ret < 0)
2008 goto deinit;
2009 }
2010
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002011 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2012 if (ret < 0)
2013 goto deinit;
2014
2015 wl1271_ps_elp_sleep(wl);
2016 }
2017deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002018 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002019 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002020 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002021 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2022 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002023
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002024 /*
2025 * this must be before the cancel_work calls below, so that the work
2026 * functions don't perform further work.
2027 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028 wl->state = WL1271_STATE_OFF;
2029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 mutex_unlock(&wl->mutex);
2031
Ido Yariva6208652011-03-01 15:14:41 +02002032 wl1271_disable_interrupts(wl);
2033 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002034 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002035 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002037 del_timer_sync(&wl->rx_streaming_timer);
2038 cancel_work_sync(&wl->rx_streaming_enable_work);
2039 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002040 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002041 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042
2043 mutex_lock(&wl->mutex);
2044
2045 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002046 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl1271_power_off(wl);
2048
2049 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002050 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002053 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002054 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055
2056 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002057 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2059 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002060 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 wl->tx_results_count = 0;
2062 wl->tx_packets_count = 0;
2063 wl->time_offset = 0;
2064 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002065 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002066 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002067 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002068 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002069 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002070 wl->ap_fw_ps_map = 0;
2071 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002072 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002073 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002074 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002075 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2076 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002077 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002078
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002079 /* The system link is always allocated */
2080 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2081
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002082 /*
2083 * this is performed after the cancel_work calls and the associated
2084 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2085 * get executed before all these vars have been reset.
2086 */
2087 wl->flags = 0;
2088
Eliad Peller4d56ad92011-08-14 13:17:05 +03002089 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002090
Arik Nemtsov742246f2011-08-14 13:17:33 +03002091 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002092 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002093 wl->tx_allocated_pkts[i] = 0;
2094 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002095
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002096 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002097
2098 kfree(wl->fw_status);
2099 wl->fw_status = NULL;
2100 kfree(wl->tx_res_if);
2101 wl->tx_res_if = NULL;
2102 kfree(wl->target_mem_map);
2103 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002104}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002105
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002106static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2107 struct ieee80211_vif *vif)
2108{
2109 struct wl1271 *wl = hw->priv;
2110
2111 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002112 /*
2113 * wl->vif can be null here if someone shuts down the interface
2114 * just when hardware recovery has been started.
2115 */
2116 if (wl->vif) {
2117 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002118 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002119 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002120
Juuso Oikarinen67353292010-11-18 15:19:02 +02002121 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002122 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002123}
2124
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002125static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002126{
2127 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002128 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002129
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002130 /*
2131 * One of the side effects of the JOIN command is that is clears
2132 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2133 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002134 * Currently the only valid scenario for JOIN during association
2135 * is on roaming, in which case we will also be given new keys.
2136 * Keep the below message for now, unless it starts bothering
2137 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002138 */
2139 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2140 wl1271_info("JOIN while associated.");
2141
2142 if (set_assoc)
2143 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2144
Eliad Peller227e81e2011-08-14 13:17:26 +03002145 if (is_ibss)
2146 ret = wl12xx_cmd_role_start_ibss(wl);
2147 else
2148 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002149 if (ret < 0)
2150 goto out;
2151
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002152 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2153 goto out;
2154
2155 /*
2156 * The join command disable the keep-alive mode, shut down its process,
2157 * and also clear the template config, so we need to reset it all after
2158 * the join. The acx_aid starts the keep-alive process, and the order
2159 * of the commands below is relevant.
2160 */
2161 ret = wl1271_acx_keep_alive_mode(wl, true);
2162 if (ret < 0)
2163 goto out;
2164
2165 ret = wl1271_acx_aid(wl, wl->aid);
2166 if (ret < 0)
2167 goto out;
2168
2169 ret = wl1271_cmd_build_klv_null_data(wl);
2170 if (ret < 0)
2171 goto out;
2172
2173 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2174 ACX_KEEP_ALIVE_TPL_VALID);
2175 if (ret < 0)
2176 goto out;
2177
2178out:
2179 return ret;
2180}
2181
2182static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002183{
2184 int ret;
2185
2186 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002187 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002188 if (ret < 0)
2189 goto out;
2190
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002191 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002192
Oz Krakowskib992c682011-06-26 10:36:02 +03002193 /* reset TX security counters on a clean disconnect */
2194 wl->tx_security_last_seq_lsb = 0;
2195 wl->tx_security_seq = 0;
2196
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002197out:
2198 return ret;
2199}
2200
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002201static void wl1271_set_band_rate(struct wl1271 *wl)
2202{
Eliad Peller53835a22011-08-23 15:56:23 +03002203 if (wl->band == IEEE80211_BAND_2GHZ) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002204 wl->basic_rate_set = wl->conf.tx.basic_rate;
Eliad Peller53835a22011-08-23 15:56:23 +03002205 wl->rate_set = wl->conf.tx.basic_rate;
2206 } else {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002207 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
Eliad Peller53835a22011-08-23 15:56:23 +03002208 wl->rate_set = wl->conf.tx.basic_rate_5;
2209 }
2210
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002211}
2212
Eliad Peller251c1772011-08-14 13:17:17 +03002213static bool wl12xx_is_roc(struct wl1271 *wl)
2214{
2215 u8 role_id;
2216
2217 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2218 if (role_id >= WL12XX_MAX_ROLES)
2219 return false;
2220
2221 return true;
2222}
2223
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002224static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002225{
2226 int ret;
2227
2228 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002229 /* no need to croc if we weren't busy (e.g. during boot) */
2230 if (wl12xx_is_roc(wl)) {
2231 ret = wl12xx_croc(wl, wl->dev_role_id);
2232 if (ret < 0)
2233 goto out;
2234
2235 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002236 if (ret < 0)
2237 goto out;
2238 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002239 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002240 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002241 if (ret < 0)
2242 goto out;
2243 ret = wl1271_acx_keep_alive_config(
2244 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2245 ACX_KEEP_ALIVE_TPL_INVALID);
2246 if (ret < 0)
2247 goto out;
2248 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2249 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002250 /* The current firmware only supports sched_scan in idle */
2251 if (wl->sched_scanning) {
2252 wl1271_scan_sched_scan_stop(wl);
2253 ieee80211_sched_scan_stopped(wl->hw);
2254 }
2255
Eliad Peller251c1772011-08-14 13:17:17 +03002256 ret = wl12xx_cmd_role_start_dev(wl);
2257 if (ret < 0)
2258 goto out;
2259
2260 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002261 if (ret < 0)
2262 goto out;
2263 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2264 }
2265
2266out:
2267 return ret;
2268}
2269
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2271{
2272 struct wl1271 *wl = hw->priv;
2273 struct ieee80211_conf *conf = &hw->conf;
2274 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002275 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276
2277 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2278
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002279 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2280 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281 channel,
2282 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002283 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002284 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2285 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002286
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002287 /*
2288 * mac80211 will go to idle nearly immediately after transmitting some
2289 * frames, such as the deauth. To make sure those frames reach the air,
2290 * wait here until the TX queue is fully flushed.
2291 */
2292 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2293 (conf->flags & IEEE80211_CONF_IDLE))
2294 wl1271_tx_flush(wl);
2295
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296 mutex_lock(&wl->mutex);
2297
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002298 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002299 /* we support configuring the channel and band while off */
2300 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2301 wl->band = conf->channel->band;
2302 wl->channel = channel;
2303 }
2304
Arik Nemtsov097f8822011-06-27 22:06:34 +03002305 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2306 wl->power_level = conf->power_level;
2307
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002308 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002309 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002310
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002311 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2312
Ido Yariva6208652011-03-01 15:14:41 +02002313 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314 if (ret < 0)
2315 goto out;
2316
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002317 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002318 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2319 ((wl->band != conf->channel->band) ||
2320 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002321 wl->band = conf->channel->band;
2322 wl->channel = channel;
2323
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002324 if (!is_ap) {
2325 /*
2326 * FIXME: the mac80211 should really provide a fixed
2327 * rate to use here. for now, just use the smallest
2328 * possible rate for the band as a fixed rate for
2329 * association frames and other control messages.
2330 */
2331 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2332 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002334 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2335 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002336 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002337 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002338 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002339
Eliad Peller251c1772011-08-14 13:17:17 +03002340 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2341 if (wl12xx_is_roc(wl)) {
2342 /* roaming */
2343 ret = wl12xx_croc(wl, wl->dev_role_id);
2344 if (ret < 0)
2345 goto out_sleep;
2346 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002347 ret = wl1271_join(wl, false);
2348 if (ret < 0)
2349 wl1271_warning("cmd join on channel "
2350 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002351 } else {
2352 /*
2353 * change the ROC channel. do it only if we are
2354 * not idle. otherwise, CROC will be called
2355 * anyway.
2356 */
2357 if (wl12xx_is_roc(wl) &&
2358 !(conf->flags & IEEE80211_CONF_IDLE)) {
2359 ret = wl12xx_croc(wl, wl->dev_role_id);
2360 if (ret < 0)
2361 goto out_sleep;
2362
2363 ret = wl12xx_roc(wl, wl->dev_role_id);
2364 if (ret < 0)
2365 wl1271_warning("roc failed %d",
2366 ret);
2367 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002368 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002369 }
2370 }
2371
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002372 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2373 ret = wl1271_sta_handle_idle(wl,
2374 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002375 if (ret < 0)
2376 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377 }
2378
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002379 /*
2380 * if mac80211 changes the PSM mode, make sure the mode is not
2381 * incorrectly changed after the pspoll failure active window.
2382 */
2383 if (changed & IEEE80211_CONF_CHANGE_PS)
2384 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2385
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002386 if (conf->flags & IEEE80211_CONF_PS &&
2387 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2388 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389
2390 /*
2391 * We enter PSM only if we're already associated.
2392 * If we're not, we'll enter it when joining an SSID,
2393 * through the bss_info_changed() hook.
2394 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002395 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002396 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002397 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002398 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002399 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002401 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002402 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002404 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002406 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002407 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002408 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409 }
2410
2411 if (conf->power_level != wl->power_level) {
2412 ret = wl1271_acx_tx_power(wl, conf->power_level);
2413 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002414 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002415
2416 wl->power_level = conf->power_level;
2417 }
2418
2419out_sleep:
2420 wl1271_ps_elp_sleep(wl);
2421
2422out:
2423 mutex_unlock(&wl->mutex);
2424
2425 return ret;
2426}
2427
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002428struct wl1271_filter_params {
2429 bool enabled;
2430 int mc_list_length;
2431 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2432};
2433
Jiri Pirko22bedad32010-04-01 21:22:57 +00002434static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2435 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002436{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002437 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002438 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002439 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002440
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002441 if (unlikely(wl->state == WL1271_STATE_OFF))
2442 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002443
Juuso Oikarinen74441132009-10-13 12:47:53 +03002444 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002445 if (!fp) {
2446 wl1271_error("Out of memory setting filters.");
2447 return 0;
2448 }
2449
2450 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002451 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002452 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2453 fp->enabled = false;
2454 } else {
2455 fp->enabled = true;
2456 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002457 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002458 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002459 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002460 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002461 }
2462
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002463 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002464}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002465
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002466#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2467 FIF_ALLMULTI | \
2468 FIF_FCSFAIL | \
2469 FIF_BCN_PRBRESP_PROMISC | \
2470 FIF_CONTROL | \
2471 FIF_OTHER_BSS)
2472
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2474 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002475 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002476{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002477 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002479 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480
Arik Nemtsov7d057862010-10-16 19:25:35 +02002481 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2482 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002484 mutex_lock(&wl->mutex);
2485
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002486 *total &= WL1271_SUPPORTED_FILTERS;
2487 changed &= WL1271_SUPPORTED_FILTERS;
2488
2489 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002490 goto out;
2491
Ido Yariva6208652011-03-01 15:14:41 +02002492 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002493 if (ret < 0)
2494 goto out;
2495
Arik Nemtsov7d057862010-10-16 19:25:35 +02002496 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2497 if (*total & FIF_ALLMULTI)
2498 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2499 else if (fp)
2500 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2501 fp->mc_list,
2502 fp->mc_list_length);
2503 if (ret < 0)
2504 goto out_sleep;
2505 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002507 /*
2508 * the fw doesn't provide an api to configure the filters. instead,
2509 * the filters configuration is based on the active roles / ROC
2510 * state.
2511 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002512
2513out_sleep:
2514 wl1271_ps_elp_sleep(wl);
2515
2516out:
2517 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002518 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519}
2520
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002521static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2522 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2523 u16 tx_seq_16)
2524{
2525 struct wl1271_ap_key *ap_key;
2526 int i;
2527
2528 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2529
2530 if (key_size > MAX_KEY_SIZE)
2531 return -EINVAL;
2532
2533 /*
2534 * Find next free entry in ap_keys. Also check we are not replacing
2535 * an existing key.
2536 */
2537 for (i = 0; i < MAX_NUM_KEYS; i++) {
2538 if (wl->recorded_ap_keys[i] == NULL)
2539 break;
2540
2541 if (wl->recorded_ap_keys[i]->id == id) {
2542 wl1271_warning("trying to record key replacement");
2543 return -EINVAL;
2544 }
2545 }
2546
2547 if (i == MAX_NUM_KEYS)
2548 return -EBUSY;
2549
2550 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2551 if (!ap_key)
2552 return -ENOMEM;
2553
2554 ap_key->id = id;
2555 ap_key->key_type = key_type;
2556 ap_key->key_size = key_size;
2557 memcpy(ap_key->key, key, key_size);
2558 ap_key->hlid = hlid;
2559 ap_key->tx_seq_32 = tx_seq_32;
2560 ap_key->tx_seq_16 = tx_seq_16;
2561
2562 wl->recorded_ap_keys[i] = ap_key;
2563 return 0;
2564}
2565
2566static void wl1271_free_ap_keys(struct wl1271 *wl)
2567{
2568 int i;
2569
2570 for (i = 0; i < MAX_NUM_KEYS; i++) {
2571 kfree(wl->recorded_ap_keys[i]);
2572 wl->recorded_ap_keys[i] = NULL;
2573 }
2574}
2575
2576static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2577{
2578 int i, ret = 0;
2579 struct wl1271_ap_key *key;
2580 bool wep_key_added = false;
2581
2582 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002583 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002584 if (wl->recorded_ap_keys[i] == NULL)
2585 break;
2586
2587 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002588 hlid = key->hlid;
2589 if (hlid == WL12XX_INVALID_LINK_ID)
2590 hlid = wl->ap_bcast_hlid;
2591
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002592 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2593 key->id, key->key_type,
2594 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002595 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002596 key->tx_seq_16);
2597 if (ret < 0)
2598 goto out;
2599
2600 if (key->key_type == KEY_WEP)
2601 wep_key_added = true;
2602 }
2603
2604 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002605 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002606 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002607 if (ret < 0)
2608 goto out;
2609 }
2610
2611out:
2612 wl1271_free_ap_keys(wl);
2613 return ret;
2614}
2615
2616static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2617 u8 key_size, const u8 *key, u32 tx_seq_32,
2618 u16 tx_seq_16, struct ieee80211_sta *sta)
2619{
2620 int ret;
2621 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2622
2623 if (is_ap) {
2624 struct wl1271_station *wl_sta;
2625 u8 hlid;
2626
2627 if (sta) {
2628 wl_sta = (struct wl1271_station *)sta->drv_priv;
2629 hlid = wl_sta->hlid;
2630 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002631 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002632 }
2633
2634 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2635 /*
2636 * We do not support removing keys after AP shutdown.
2637 * Pretend we do to make mac80211 happy.
2638 */
2639 if (action != KEY_ADD_OR_REPLACE)
2640 return 0;
2641
2642 ret = wl1271_record_ap_key(wl, id,
2643 key_type, key_size,
2644 key, hlid, tx_seq_32,
2645 tx_seq_16);
2646 } else {
2647 ret = wl1271_cmd_set_ap_key(wl, action,
2648 id, key_type, key_size,
2649 key, hlid, tx_seq_32,
2650 tx_seq_16);
2651 }
2652
2653 if (ret < 0)
2654 return ret;
2655 } else {
2656 const u8 *addr;
2657 static const u8 bcast_addr[ETH_ALEN] = {
2658 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2659 };
2660
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002661 /*
2662 * A STA set to GEM cipher requires 2 tx spare blocks.
2663 * Return to default value when GEM cipher key is removed
2664 */
2665 if (key_type == KEY_GEM) {
2666 if (action == KEY_ADD_OR_REPLACE)
2667 wl->tx_spare_blocks = 2;
2668 else if (action == KEY_REMOVE)
2669 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2670 }
2671
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002672 addr = sta ? sta->addr : bcast_addr;
2673
2674 if (is_zero_ether_addr(addr)) {
2675 /* We dont support TX only encryption */
2676 return -EOPNOTSUPP;
2677 }
2678
2679 /* The wl1271 does not allow to remove unicast keys - they
2680 will be cleared automatically on next CMD_JOIN. Ignore the
2681 request silently, as we dont want the mac80211 to emit
2682 an error message. */
2683 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2684 return 0;
2685
Eliad Peller010d3d32011-08-14 13:17:31 +03002686 /* don't remove key if hlid was already deleted */
2687 if (action == KEY_REMOVE &&
2688 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2689 return 0;
2690
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002691 ret = wl1271_cmd_set_sta_key(wl, action,
2692 id, key_type, key_size,
2693 key, addr, tx_seq_32,
2694 tx_seq_16);
2695 if (ret < 0)
2696 return ret;
2697
2698 /* the default WEP key needs to be configured at least once */
2699 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002700 ret = wl12xx_cmd_set_default_wep_key(wl,
2701 wl->default_key,
2702 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002703 if (ret < 0)
2704 return ret;
2705 }
2706 }
2707
2708 return 0;
2709}
2710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002711static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2712 struct ieee80211_vif *vif,
2713 struct ieee80211_sta *sta,
2714 struct ieee80211_key_conf *key_conf)
2715{
2716 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002718 u32 tx_seq_32 = 0;
2719 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720 u8 key_type;
2721
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2723
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002724 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002726 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002727 key_conf->keylen, key_conf->flags);
2728 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2729
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730 mutex_lock(&wl->mutex);
2731
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002732 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2733 ret = -EAGAIN;
2734 goto out_unlock;
2735 }
2736
Ido Yariva6208652011-03-01 15:14:41 +02002737 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738 if (ret < 0)
2739 goto out_unlock;
2740
Johannes Berg97359d12010-08-10 09:46:38 +02002741 switch (key_conf->cipher) {
2742 case WLAN_CIPHER_SUITE_WEP40:
2743 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002744 key_type = KEY_WEP;
2745
2746 key_conf->hw_key_idx = key_conf->keyidx;
2747 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002748 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749 key_type = KEY_TKIP;
2750
2751 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002752 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2753 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002754 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002755 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002756 key_type = KEY_AES;
2757
2758 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002759 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2760 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002762 case WL1271_CIPHER_SUITE_GEM:
2763 key_type = KEY_GEM;
2764 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2765 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2766 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002767 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002768 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002769
2770 ret = -EOPNOTSUPP;
2771 goto out_sleep;
2772 }
2773
2774 switch (cmd) {
2775 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002776 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2777 key_conf->keyidx, key_type,
2778 key_conf->keylen, key_conf->key,
2779 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002780 if (ret < 0) {
2781 wl1271_error("Could not add or replace key");
2782 goto out_sleep;
2783 }
2784 break;
2785
2786 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 ret = wl1271_set_key(wl, KEY_REMOVE,
2788 key_conf->keyidx, key_type,
2789 key_conf->keylen, key_conf->key,
2790 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002791 if (ret < 0) {
2792 wl1271_error("Could not remove key");
2793 goto out_sleep;
2794 }
2795 break;
2796
2797 default:
2798 wl1271_error("Unsupported key cmd 0x%x", cmd);
2799 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002800 break;
2801 }
2802
2803out_sleep:
2804 wl1271_ps_elp_sleep(wl);
2805
2806out_unlock:
2807 mutex_unlock(&wl->mutex);
2808
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 return ret;
2810}
2811
2812static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002813 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002814 struct cfg80211_scan_request *req)
2815{
2816 struct wl1271 *wl = hw->priv;
2817 int ret;
2818 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002819 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002820
2821 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2822
2823 if (req->n_ssids) {
2824 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002825 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826 }
2827
2828 mutex_lock(&wl->mutex);
2829
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002830 if (wl->state == WL1271_STATE_OFF) {
2831 /*
2832 * We cannot return -EBUSY here because cfg80211 will expect
2833 * a call to ieee80211_scan_completed if we do - in this case
2834 * there won't be any call.
2835 */
2836 ret = -EAGAIN;
2837 goto out;
2838 }
2839
Ido Yariva6208652011-03-01 15:14:41 +02002840 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841 if (ret < 0)
2842 goto out;
2843
Eliad Peller251c1772011-08-14 13:17:17 +03002844 /* cancel ROC before scanning */
2845 if (wl12xx_is_roc(wl)) {
2846 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2847 /* don't allow scanning right now */
2848 ret = -EBUSY;
2849 goto out_sleep;
2850 }
2851 wl12xx_croc(wl, wl->dev_role_id);
2852 wl12xx_cmd_role_stop_dev(wl);
2853 }
2854
Luciano Coelho5924f892010-08-04 03:46:22 +03002855 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002856out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002857 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002858out:
2859 mutex_unlock(&wl->mutex);
2860
2861 return ret;
2862}
2863
Eliad Peller73ecce32011-06-27 13:06:45 +03002864static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2865 struct ieee80211_vif *vif)
2866{
2867 struct wl1271 *wl = hw->priv;
2868 int ret;
2869
2870 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2871
2872 mutex_lock(&wl->mutex);
2873
2874 if (wl->state == WL1271_STATE_OFF)
2875 goto out;
2876
2877 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2878 goto out;
2879
2880 ret = wl1271_ps_elp_wakeup(wl);
2881 if (ret < 0)
2882 goto out;
2883
2884 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2885 ret = wl1271_scan_stop(wl);
2886 if (ret < 0)
2887 goto out_sleep;
2888 }
2889 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2890 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2891 wl->scan.req = NULL;
2892 ieee80211_scan_completed(wl->hw, true);
2893
2894out_sleep:
2895 wl1271_ps_elp_sleep(wl);
2896out:
2897 mutex_unlock(&wl->mutex);
2898
2899 cancel_delayed_work_sync(&wl->scan_complete_work);
2900}
2901
Luciano Coelho33c2c062011-05-10 14:46:02 +03002902static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2903 struct ieee80211_vif *vif,
2904 struct cfg80211_sched_scan_request *req,
2905 struct ieee80211_sched_scan_ies *ies)
2906{
2907 struct wl1271 *wl = hw->priv;
2908 int ret;
2909
2910 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2911
2912 mutex_lock(&wl->mutex);
2913
2914 ret = wl1271_ps_elp_wakeup(wl);
2915 if (ret < 0)
2916 goto out;
2917
2918 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2919 if (ret < 0)
2920 goto out_sleep;
2921
2922 ret = wl1271_scan_sched_scan_start(wl);
2923 if (ret < 0)
2924 goto out_sleep;
2925
2926 wl->sched_scanning = true;
2927
2928out_sleep:
2929 wl1271_ps_elp_sleep(wl);
2930out:
2931 mutex_unlock(&wl->mutex);
2932 return ret;
2933}
2934
2935static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2936 struct ieee80211_vif *vif)
2937{
2938 struct wl1271 *wl = hw->priv;
2939 int ret;
2940
2941 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2942
2943 mutex_lock(&wl->mutex);
2944
2945 ret = wl1271_ps_elp_wakeup(wl);
2946 if (ret < 0)
2947 goto out;
2948
2949 wl1271_scan_sched_scan_stop(wl);
2950
2951 wl1271_ps_elp_sleep(wl);
2952out:
2953 mutex_unlock(&wl->mutex);
2954}
2955
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002956static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2957{
2958 struct wl1271 *wl = hw->priv;
2959 int ret = 0;
2960
2961 mutex_lock(&wl->mutex);
2962
2963 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2964 ret = -EAGAIN;
2965 goto out;
2966 }
2967
Ido Yariva6208652011-03-01 15:14:41 +02002968 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002969 if (ret < 0)
2970 goto out;
2971
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002972 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002973 if (ret < 0)
2974 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2975
2976 wl1271_ps_elp_sleep(wl);
2977
2978out:
2979 mutex_unlock(&wl->mutex);
2980
2981 return ret;
2982}
2983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2985{
2986 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002987 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988
2989 mutex_lock(&wl->mutex);
2990
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002991 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2992 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002993 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002994 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002995
Ido Yariva6208652011-03-01 15:14:41 +02002996 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002997 if (ret < 0)
2998 goto out;
2999
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003000 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003001 if (ret < 0)
3002 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3003
3004 wl1271_ps_elp_sleep(wl);
3005
3006out:
3007 mutex_unlock(&wl->mutex);
3008
3009 return ret;
3010}
3011
Arik Nemtsove78a2872010-10-16 19:07:21 +02003012static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003013 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003014{
Eliad Peller889cb362011-05-01 09:56:45 +03003015 u8 ssid_len;
3016 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3017 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003018
Eliad Peller889cb362011-05-01 09:56:45 +03003019 if (!ptr) {
3020 wl1271_error("No SSID in IEs!");
3021 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003022 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003023
Eliad Peller889cb362011-05-01 09:56:45 +03003024 ssid_len = ptr[1];
3025 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3026 wl1271_error("SSID is too long!");
3027 return -EINVAL;
3028 }
3029
3030 wl->ssid_len = ssid_len;
3031 memcpy(wl->ssid, ptr+2, ssid_len);
3032 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003033}
3034
Arik Nemtsove78a2872010-10-16 19:07:21 +02003035static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3036 struct ieee80211_bss_conf *bss_conf,
3037 u32 changed)
3038{
3039 int ret = 0;
3040
3041 if (changed & BSS_CHANGED_ERP_SLOT) {
3042 if (bss_conf->use_short_slot)
3043 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3044 else
3045 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3046 if (ret < 0) {
3047 wl1271_warning("Set slot time failed %d", ret);
3048 goto out;
3049 }
3050 }
3051
3052 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3053 if (bss_conf->use_short_preamble)
3054 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3055 else
3056 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3057 }
3058
3059 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3060 if (bss_conf->use_cts_prot)
3061 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3062 else
3063 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3064 if (ret < 0) {
3065 wl1271_warning("Set ctsprotect failed %d", ret);
3066 goto out;
3067 }
3068 }
3069
3070out:
3071 return ret;
3072}
3073
3074static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3075 struct ieee80211_vif *vif,
3076 struct ieee80211_bss_conf *bss_conf,
3077 u32 changed)
3078{
3079 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3080 int ret = 0;
3081
3082 if ((changed & BSS_CHANGED_BEACON_INT)) {
3083 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3084 bss_conf->beacon_int);
3085
3086 wl->beacon_int = bss_conf->beacon_int;
3087 }
3088
3089 if ((changed & BSS_CHANGED_BEACON)) {
3090 struct ieee80211_hdr *hdr;
3091 int ieoffset = offsetof(struct ieee80211_mgmt,
3092 u.beacon.variable);
3093 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3094 u16 tmpl_id;
3095
3096 if (!beacon)
3097 goto out;
3098
3099 wl1271_debug(DEBUG_MASTER, "beacon updated");
3100
3101 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3102 if (ret < 0) {
3103 dev_kfree_skb(beacon);
3104 goto out;
3105 }
3106 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3107 CMD_TEMPL_BEACON;
3108 ret = wl1271_cmd_template_set(wl, tmpl_id,
3109 beacon->data,
3110 beacon->len, 0,
3111 wl1271_tx_min_rate_get(wl));
3112 if (ret < 0) {
3113 dev_kfree_skb(beacon);
3114 goto out;
3115 }
3116
3117 hdr = (struct ieee80211_hdr *) beacon->data;
3118 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3119 IEEE80211_STYPE_PROBE_RESP);
3120
3121 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3122 CMD_TEMPL_PROBE_RESPONSE;
3123 ret = wl1271_cmd_template_set(wl,
3124 tmpl_id,
3125 beacon->data,
3126 beacon->len, 0,
3127 wl1271_tx_min_rate_get(wl));
3128 dev_kfree_skb(beacon);
3129 if (ret < 0)
3130 goto out;
3131 }
3132
3133out:
3134 return ret;
3135}
3136
3137/* AP mode changes */
3138static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003139 struct ieee80211_vif *vif,
3140 struct ieee80211_bss_conf *bss_conf,
3141 u32 changed)
3142{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003143 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003144
Arik Nemtsove78a2872010-10-16 19:07:21 +02003145 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3146 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003147
Arik Nemtsove78a2872010-10-16 19:07:21 +02003148 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3149 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003150
Arik Nemtsov70f47422011-04-18 14:15:25 +03003151 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003152 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003153 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003154 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003155 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003156
3157 ret = wl1271_ap_init_templates(wl);
3158 if (ret < 0)
3159 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003160 }
3161
Arik Nemtsove78a2872010-10-16 19:07:21 +02003162 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3163 if (ret < 0)
3164 goto out;
3165
3166 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3167 if (bss_conf->enable_beacon) {
3168 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003169 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003170 if (ret < 0)
3171 goto out;
3172
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003173 ret = wl1271_ap_init_hwenc(wl);
3174 if (ret < 0)
3175 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003176
3177 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3178 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003179 }
3180 } else {
3181 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003182 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003183 if (ret < 0)
3184 goto out;
3185
3186 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3187 wl1271_debug(DEBUG_AP, "stopped AP");
3188 }
3189 }
3190 }
3191
3192 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3193 if (ret < 0)
3194 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003195
3196 /* Handle HT information change */
3197 if ((changed & BSS_CHANGED_HT) &&
3198 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3199 ret = wl1271_acx_set_ht_information(wl,
3200 bss_conf->ht_operation_mode);
3201 if (ret < 0) {
3202 wl1271_warning("Set ht information failed %d", ret);
3203 goto out;
3204 }
3205 }
3206
Arik Nemtsove78a2872010-10-16 19:07:21 +02003207out:
3208 return;
3209}
3210
3211/* STA/IBSS mode changes */
3212static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3213 struct ieee80211_vif *vif,
3214 struct ieee80211_bss_conf *bss_conf,
3215 u32 changed)
3216{
3217 bool do_join = false, set_assoc = false;
3218 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003219 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003220 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003221 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003222 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003223 bool sta_exists = false;
3224 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003225
3226 if (is_ibss) {
3227 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3228 changed);
3229 if (ret < 0)
3230 goto out;
3231 }
3232
Eliad Peller227e81e2011-08-14 13:17:26 +03003233 if (changed & BSS_CHANGED_IBSS) {
3234 if (bss_conf->ibss_joined) {
3235 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3236 ibss_joined = true;
3237 } else {
3238 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3239 &wl->flags)) {
3240 wl1271_unjoin(wl);
3241 wl12xx_cmd_role_start_dev(wl);
3242 wl12xx_roc(wl, wl->dev_role_id);
3243 }
3244 }
3245 }
3246
3247 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003248 do_join = true;
3249
3250 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003251 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003252 do_join = true;
3253
Eliad Peller227e81e2011-08-14 13:17:26 +03003254 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003255 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3256 bss_conf->enable_beacon ? "enabled" : "disabled");
3257
3258 if (bss_conf->enable_beacon)
3259 wl->set_bss_type = BSS_TYPE_IBSS;
3260 else
3261 wl->set_bss_type = BSS_TYPE_STA_BSS;
3262 do_join = true;
3263 }
3264
Arik Nemtsove78a2872010-10-16 19:07:21 +02003265 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003266 bool enable = false;
3267 if (bss_conf->cqm_rssi_thold)
3268 enable = true;
3269 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3270 bss_conf->cqm_rssi_thold,
3271 bss_conf->cqm_rssi_hyst);
3272 if (ret < 0)
3273 goto out;
3274 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3275 }
3276
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003277 if ((changed & BSS_CHANGED_BSSID) &&
3278 /*
3279 * Now we know the correct bssid, so we send a new join command
3280 * and enable the BSSID filter
3281 */
3282 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003283 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003284
Eliad Pellerfa287b82010-12-26 09:27:50 +01003285 if (!is_zero_ether_addr(wl->bssid)) {
3286 ret = wl1271_cmd_build_null_data(wl);
3287 if (ret < 0)
3288 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003289
Eliad Pellerfa287b82010-12-26 09:27:50 +01003290 ret = wl1271_build_qos_null_data(wl);
3291 if (ret < 0)
3292 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003293
Eliad Pellerfa287b82010-12-26 09:27:50 +01003294 /* Need to update the BSSID (for filtering etc) */
3295 do_join = true;
3296 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003297 }
3298
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003299 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3300 rcu_read_lock();
3301 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3302 if (!sta)
3303 goto sta_not_found;
3304
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003305 /* save the supp_rates of the ap */
3306 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3307 if (sta->ht_cap.ht_supported)
3308 sta_rate_set |=
3309 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003310 sta_ht_cap = sta->ht_cap;
3311 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003312
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003313sta_not_found:
3314 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003315 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003316
Arik Nemtsove78a2872010-10-16 19:07:21 +02003317 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003318 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003319 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003320 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003321 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003322 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003323
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003324 wl->ps_poll_failures = 0;
3325
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003326 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003327 * use basic rates from AP, and determine lowest rate
3328 * to use with control frames.
3329 */
3330 rates = bss_conf->basic_rates;
3331 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3332 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003333 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003334 if (sta_rate_set)
3335 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3336 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003337 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003338 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003339 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003340
3341 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003342 * with wl1271, we don't need to update the
3343 * beacon_int and dtim_period, because the firmware
3344 * updates it by itself when the first beacon is
3345 * received after a join.
3346 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003347 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3348 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003350
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003351 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003352 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003353 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003354 dev_kfree_skb(wl->probereq);
3355 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3356 ieoffset = offsetof(struct ieee80211_mgmt,
3357 u.probe_req.variable);
3358 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003359
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003360 /* enable the connection monitoring feature */
3361 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003362 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003364 } else {
3365 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003366 bool was_assoc =
3367 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3368 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003369 bool was_ifup =
3370 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3371 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003372 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003373
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003374 /* free probe-request template */
3375 dev_kfree_skb(wl->probereq);
3376 wl->probereq = NULL;
3377
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003378 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003379 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003380
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003381 /* revert back to minimum rates for the current band */
3382 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003383 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003384 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003385 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003387
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003388 /* disable connection monitor features */
3389 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003390
3391 /* Disable the keep-alive feature */
3392 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003393 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003395
3396 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003397 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003398 u32 conf_flags = wl->hw->conf.flags;
3399 /*
3400 * we might have to disable roc, if there was
3401 * no IF_OPER_UP notification.
3402 */
3403 if (!was_ifup) {
3404 ret = wl12xx_croc(wl, wl->role_id);
3405 if (ret < 0)
3406 goto out;
3407 }
3408 /*
3409 * (we also need to disable roc in case of
3410 * roaming on the same channel. until we will
3411 * have a better flow...)
3412 */
3413 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3414 ret = wl12xx_croc(wl, wl->dev_role_id);
3415 if (ret < 0)
3416 goto out;
3417 }
3418
Eliad Peller30df14d2011-04-05 19:13:28 +03003419 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003420 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3421 wl12xx_cmd_role_start_dev(wl);
3422 wl12xx_roc(wl, wl->dev_role_id);
3423 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003424 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003425 }
3426 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003427
Eliad Pellerd192d262011-05-24 14:33:08 +03003428 if (changed & BSS_CHANGED_IBSS) {
3429 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3430 bss_conf->ibss_joined);
3431
3432 if (bss_conf->ibss_joined) {
3433 u32 rates = bss_conf->basic_rates;
3434 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3435 rates);
3436 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3437
3438 /* by default, use 11b rates */
3439 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3440 ret = wl1271_acx_sta_rate_policies(wl);
3441 if (ret < 0)
3442 goto out;
3443 }
3444 }
3445
Arik Nemtsove78a2872010-10-16 19:07:21 +02003446 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3447 if (ret < 0)
3448 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003450 if (changed & BSS_CHANGED_ARP_FILTER) {
3451 __be32 addr = bss_conf->arp_addr_list[0];
3452 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3453
Eliad Pellerc5312772010-12-09 11:31:27 +02003454 if (bss_conf->arp_addr_cnt == 1 &&
3455 bss_conf->arp_filter_enabled) {
3456 /*
3457 * The template should have been configured only upon
3458 * association. however, it seems that the correct ip
3459 * isn't being set (when sending), so we have to
3460 * reconfigure the template upon every ip change.
3461 */
3462 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3463 if (ret < 0) {
3464 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003465 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003466 }
3467
3468 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003469 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003470 addr);
3471 } else
3472 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003473
3474 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003475 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003476 }
3477
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003478 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003479 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003480 if (ret < 0) {
3481 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003482 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003483 }
Eliad Peller251c1772011-08-14 13:17:17 +03003484
3485 /* ROC until connected (after EAPOL exchange) */
3486 if (!is_ibss) {
3487 ret = wl12xx_roc(wl, wl->role_id);
3488 if (ret < 0)
3489 goto out;
3490
3491 wl1271_check_operstate(wl,
3492 ieee80211_get_operstate(vif));
3493 }
3494 /*
3495 * stop device role if started (we might already be in
3496 * STA role). TODO: make it better.
3497 */
3498 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3499 ret = wl12xx_croc(wl, wl->dev_role_id);
3500 if (ret < 0)
3501 goto out;
3502
3503 ret = wl12xx_cmd_role_stop_dev(wl);
3504 if (ret < 0)
3505 goto out;
3506 }
Eliad Peller05dba352011-08-23 16:37:01 +03003507
3508 /* If we want to go in PSM but we're not there yet */
3509 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3510 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3511 enum wl1271_cmd_ps_mode mode;
3512
3513 mode = STATION_POWER_SAVE_MODE;
3514 ret = wl1271_ps_set_mode(wl, mode,
3515 wl->basic_rate,
3516 true);
3517 if (ret < 0)
3518 goto out;
3519 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003520 }
3521
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003522 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003523 if (sta_exists) {
3524 if ((changed & BSS_CHANGED_HT) &&
3525 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003526 ret = wl1271_acx_set_ht_capabilities(wl,
3527 &sta_ht_cap,
3528 true,
3529 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003530 if (ret < 0) {
3531 wl1271_warning("Set ht cap true failed %d",
3532 ret);
3533 goto out;
3534 }
3535 }
3536 /* handle new association without HT and disassociation */
3537 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003538 ret = wl1271_acx_set_ht_capabilities(wl,
3539 &sta_ht_cap,
3540 false,
3541 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003542 if (ret < 0) {
3543 wl1271_warning("Set ht cap false failed %d",
3544 ret);
3545 goto out;
3546 }
3547 }
3548 }
3549
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003550 /* Handle HT information change. Done after join. */
3551 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003552 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3553 ret = wl1271_acx_set_ht_information(wl,
3554 bss_conf->ht_operation_mode);
3555 if (ret < 0) {
3556 wl1271_warning("Set ht information failed %d", ret);
3557 goto out;
3558 }
3559 }
3560
Arik Nemtsove78a2872010-10-16 19:07:21 +02003561out:
3562 return;
3563}
3564
3565static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3566 struct ieee80211_vif *vif,
3567 struct ieee80211_bss_conf *bss_conf,
3568 u32 changed)
3569{
3570 struct wl1271 *wl = hw->priv;
3571 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3572 int ret;
3573
3574 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3575 (int)changed);
3576
3577 mutex_lock(&wl->mutex);
3578
3579 if (unlikely(wl->state == WL1271_STATE_OFF))
3580 goto out;
3581
Ido Yariva6208652011-03-01 15:14:41 +02003582 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003583 if (ret < 0)
3584 goto out;
3585
3586 if (is_ap)
3587 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3588 else
3589 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3590
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003591 wl1271_ps_elp_sleep(wl);
3592
3593out:
3594 mutex_unlock(&wl->mutex);
3595}
3596
Kalle Valoc6999d82010-02-18 13:25:41 +02003597static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3598 const struct ieee80211_tx_queue_params *params)
3599{
3600 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003601 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003602 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003603
3604 mutex_lock(&wl->mutex);
3605
3606 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3607
Kalle Valo4695dc92010-03-18 12:26:38 +02003608 if (params->uapsd)
3609 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3610 else
3611 ps_scheme = CONF_PS_SCHEME_LEGACY;
3612
Arik Nemtsov488fc542010-10-16 20:33:45 +02003613 if (wl->state == WL1271_STATE_OFF) {
3614 /*
3615 * If the state is off, the parameters will be recorded and
3616 * configured on init. This happens in AP-mode.
3617 */
3618 struct conf_tx_ac_category *conf_ac =
3619 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3620 struct conf_tx_tid *conf_tid =
3621 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3622
3623 conf_ac->ac = wl1271_tx_get_queue(queue);
3624 conf_ac->cw_min = (u8)params->cw_min;
3625 conf_ac->cw_max = params->cw_max;
3626 conf_ac->aifsn = params->aifs;
3627 conf_ac->tx_op_limit = params->txop << 5;
3628
3629 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3630 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3631 conf_tid->tsid = wl1271_tx_get_queue(queue);
3632 conf_tid->ps_scheme = ps_scheme;
3633 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3634 conf_tid->apsd_conf[0] = 0;
3635 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003636 goto out;
3637 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003638
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003639 ret = wl1271_ps_elp_wakeup(wl);
3640 if (ret < 0)
3641 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003642
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003643 /*
3644 * the txop is confed in units of 32us by the mac80211,
3645 * we need us
3646 */
3647 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3648 params->cw_min, params->cw_max,
3649 params->aifs, params->txop << 5);
3650 if (ret < 0)
3651 goto out_sleep;
3652
3653 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3654 CONF_CHANNEL_TYPE_EDCF,
3655 wl1271_tx_get_queue(queue),
3656 ps_scheme, CONF_ACK_POLICY_LEGACY,
3657 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003658
3659out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003660 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003661
3662out:
3663 mutex_unlock(&wl->mutex);
3664
3665 return ret;
3666}
3667
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003668static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3669{
3670
3671 struct wl1271 *wl = hw->priv;
3672 u64 mactime = ULLONG_MAX;
3673 int ret;
3674
3675 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3676
3677 mutex_lock(&wl->mutex);
3678
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003679 if (unlikely(wl->state == WL1271_STATE_OFF))
3680 goto out;
3681
Ido Yariva6208652011-03-01 15:14:41 +02003682 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003683 if (ret < 0)
3684 goto out;
3685
3686 ret = wl1271_acx_tsf_info(wl, &mactime);
3687 if (ret < 0)
3688 goto out_sleep;
3689
3690out_sleep:
3691 wl1271_ps_elp_sleep(wl);
3692
3693out:
3694 mutex_unlock(&wl->mutex);
3695 return mactime;
3696}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003697
John W. Linvilleece550d2010-07-28 16:41:06 -04003698static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3699 struct survey_info *survey)
3700{
3701 struct wl1271 *wl = hw->priv;
3702 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003703
John W. Linvilleece550d2010-07-28 16:41:06 -04003704 if (idx != 0)
3705 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003706
John W. Linvilleece550d2010-07-28 16:41:06 -04003707 survey->channel = conf->channel;
3708 survey->filled = SURVEY_INFO_NOISE_DBM;
3709 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003710
John W. Linvilleece550d2010-07-28 16:41:06 -04003711 return 0;
3712}
3713
Arik Nemtsov409622e2011-02-23 00:22:29 +02003714static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003715 struct ieee80211_sta *sta,
3716 u8 *hlid)
3717{
3718 struct wl1271_station *wl_sta;
3719 int id;
3720
3721 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3722 if (id >= AP_MAX_STATIONS) {
3723 wl1271_warning("could not allocate HLID - too much stations");
3724 return -EBUSY;
3725 }
3726
3727 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003728 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003729 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3730 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003731 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003732 return 0;
3733}
3734
Arik Nemtsov409622e2011-02-23 00:22:29 +02003735static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003736{
3737 int id = hlid - WL1271_AP_STA_HLID_START;
3738
Arik Nemtsov409622e2011-02-23 00:22:29 +02003739 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3740 return;
3741
Arik Nemtsov04216da2011-08-14 13:17:38 +03003742 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003743 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003744 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003745 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003746 __clear_bit(hlid, &wl->ap_ps_map);
3747 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003748}
3749
3750static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3751 struct ieee80211_vif *vif,
3752 struct ieee80211_sta *sta)
3753{
3754 struct wl1271 *wl = hw->priv;
3755 int ret = 0;
3756 u8 hlid;
3757
3758 mutex_lock(&wl->mutex);
3759
3760 if (unlikely(wl->state == WL1271_STATE_OFF))
3761 goto out;
3762
3763 if (wl->bss_type != BSS_TYPE_AP_BSS)
3764 goto out;
3765
3766 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3767
Arik Nemtsov409622e2011-02-23 00:22:29 +02003768 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003769 if (ret < 0)
3770 goto out;
3771
Ido Yariva6208652011-03-01 15:14:41 +02003772 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003773 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003774 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003775
Eliad Pellerc690ec82011-08-14 13:17:07 +03003776 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003777 if (ret < 0)
3778 goto out_sleep;
3779
Eliad Pellerb67476e2011-08-14 13:17:23 +03003780 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3781 if (ret < 0)
3782 goto out_sleep;
3783
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003784 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3785 if (ret < 0)
3786 goto out_sleep;
3787
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003788out_sleep:
3789 wl1271_ps_elp_sleep(wl);
3790
Arik Nemtsov409622e2011-02-23 00:22:29 +02003791out_free_sta:
3792 if (ret < 0)
3793 wl1271_free_sta(wl, hlid);
3794
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003795out:
3796 mutex_unlock(&wl->mutex);
3797 return ret;
3798}
3799
3800static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3801 struct ieee80211_vif *vif,
3802 struct ieee80211_sta *sta)
3803{
3804 struct wl1271 *wl = hw->priv;
3805 struct wl1271_station *wl_sta;
3806 int ret = 0, id;
3807
3808 mutex_lock(&wl->mutex);
3809
3810 if (unlikely(wl->state == WL1271_STATE_OFF))
3811 goto out;
3812
3813 if (wl->bss_type != BSS_TYPE_AP_BSS)
3814 goto out;
3815
3816 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3817
3818 wl_sta = (struct wl1271_station *)sta->drv_priv;
3819 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3820 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3821 goto out;
3822
Ido Yariva6208652011-03-01 15:14:41 +02003823 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003824 if (ret < 0)
3825 goto out;
3826
Eliad Pellerc690ec82011-08-14 13:17:07 +03003827 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003828 if (ret < 0)
3829 goto out_sleep;
3830
Arik Nemtsov409622e2011-02-23 00:22:29 +02003831 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003832
3833out_sleep:
3834 wl1271_ps_elp_sleep(wl);
3835
3836out:
3837 mutex_unlock(&wl->mutex);
3838 return ret;
3839}
3840
Luciano Coelho4623ec72011-03-21 19:26:41 +02003841static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3842 struct ieee80211_vif *vif,
3843 enum ieee80211_ampdu_mlme_action action,
3844 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3845 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003846{
3847 struct wl1271 *wl = hw->priv;
3848 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003849 u8 hlid, *ba_bitmap;
3850
3851 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3852 tid);
3853
3854 /* sanity check - the fields in FW are only 8bits wide */
3855 if (WARN_ON(tid > 0xFF))
3856 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003857
3858 mutex_lock(&wl->mutex);
3859
3860 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3861 ret = -EAGAIN;
3862 goto out;
3863 }
3864
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003865 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3866 hlid = wl->sta_hlid;
3867 ba_bitmap = &wl->ba_rx_bitmap;
3868 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3869 struct wl1271_station *wl_sta;
3870
3871 wl_sta = (struct wl1271_station *)sta->drv_priv;
3872 hlid = wl_sta->hlid;
3873 ba_bitmap = &wl->links[hlid].ba_bitmap;
3874 } else {
3875 ret = -EINVAL;
3876 goto out;
3877 }
3878
Ido Yariva6208652011-03-01 15:14:41 +02003879 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003880 if (ret < 0)
3881 goto out;
3882
Shahar Levi70559a02011-05-22 16:10:22 +03003883 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3884 tid, action);
3885
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003886 switch (action) {
3887 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003888 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003889 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003890 break;
3891 }
3892
3893 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3894 ret = -EBUSY;
3895 wl1271_error("exceeded max RX BA sessions");
3896 break;
3897 }
3898
3899 if (*ba_bitmap & BIT(tid)) {
3900 ret = -EINVAL;
3901 wl1271_error("cannot enable RX BA session on active "
3902 "tid: %d", tid);
3903 break;
3904 }
3905
3906 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3907 hlid);
3908 if (!ret) {
3909 *ba_bitmap |= BIT(tid);
3910 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003911 }
3912 break;
3913
3914 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003915 if (!(*ba_bitmap & BIT(tid))) {
3916 ret = -EINVAL;
3917 wl1271_error("no active RX BA session on tid: %d",
3918 tid);
3919 break;
3920 }
3921
3922 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3923 hlid);
3924 if (!ret) {
3925 *ba_bitmap &= ~BIT(tid);
3926 wl->ba_rx_session_count--;
3927 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003928 break;
3929
3930 /*
3931 * The BA initiator session management in FW independently.
3932 * Falling break here on purpose for all TX APDU commands.
3933 */
3934 case IEEE80211_AMPDU_TX_START:
3935 case IEEE80211_AMPDU_TX_STOP:
3936 case IEEE80211_AMPDU_TX_OPERATIONAL:
3937 ret = -EINVAL;
3938 break;
3939
3940 default:
3941 wl1271_error("Incorrect ampdu action id=%x\n", action);
3942 ret = -EINVAL;
3943 }
3944
3945 wl1271_ps_elp_sleep(wl);
3946
3947out:
3948 mutex_unlock(&wl->mutex);
3949
3950 return ret;
3951}
3952
Arik Nemtsov33437892011-04-26 23:35:39 +03003953static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3954{
3955 struct wl1271 *wl = hw->priv;
3956 bool ret = false;
3957
3958 mutex_lock(&wl->mutex);
3959
3960 if (unlikely(wl->state == WL1271_STATE_OFF))
3961 goto out;
3962
3963 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003964 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003965
3966 /* the above is appropriate for STA mode for PS purposes */
3967 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3968
3969out:
3970 mutex_unlock(&wl->mutex);
3971
3972 return ret;
3973}
3974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003975/* can't be const, mac80211 writes to this */
3976static struct ieee80211_rate wl1271_rates[] = {
3977 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003978 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3979 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003980 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003981 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3982 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003983 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3984 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003985 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3986 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003987 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3988 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003989 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3990 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003991 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3992 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003993 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3994 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003995 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003996 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3997 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003998 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003999 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4000 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004001 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004002 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4003 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004004 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004005 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4006 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004007 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004008 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4009 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004010 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004011 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4012 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004013 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004014 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4015 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004016};
4017
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004018/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004019static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004020 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004021 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004022 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4023 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4024 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004025 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004026 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4027 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4028 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004029 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004030 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4031 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4032 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004033 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004034};
4035
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004036/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004037static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004038 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004039 7, /* CONF_HW_RXTX_RATE_MCS7 */
4040 6, /* CONF_HW_RXTX_RATE_MCS6 */
4041 5, /* CONF_HW_RXTX_RATE_MCS5 */
4042 4, /* CONF_HW_RXTX_RATE_MCS4 */
4043 3, /* CONF_HW_RXTX_RATE_MCS3 */
4044 2, /* CONF_HW_RXTX_RATE_MCS2 */
4045 1, /* CONF_HW_RXTX_RATE_MCS1 */
4046 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004047
4048 11, /* CONF_HW_RXTX_RATE_54 */
4049 10, /* CONF_HW_RXTX_RATE_48 */
4050 9, /* CONF_HW_RXTX_RATE_36 */
4051 8, /* CONF_HW_RXTX_RATE_24 */
4052
4053 /* TI-specific rate */
4054 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4055
4056 7, /* CONF_HW_RXTX_RATE_18 */
4057 6, /* CONF_HW_RXTX_RATE_12 */
4058 3, /* CONF_HW_RXTX_RATE_11 */
4059 5, /* CONF_HW_RXTX_RATE_9 */
4060 4, /* CONF_HW_RXTX_RATE_6 */
4061 2, /* CONF_HW_RXTX_RATE_5_5 */
4062 1, /* CONF_HW_RXTX_RATE_2 */
4063 0 /* CONF_HW_RXTX_RATE_1 */
4064};
4065
Shahar Levie8b03a22010-10-13 16:09:39 +02004066/* 11n STA capabilities */
4067#define HW_RX_HIGHEST_RATE 72
4068
Shahar Levi00d20102010-11-08 11:20:10 +00004069#ifdef CONFIG_WL12XX_HT
4070#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004071 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4072 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004073 .ht_supported = true, \
4074 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4075 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4076 .mcs = { \
4077 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4078 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4079 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4080 }, \
4081}
Shahar Levi18357852010-10-13 16:09:41 +02004082#else
Shahar Levi00d20102010-11-08 11:20:10 +00004083#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004084 .ht_supported = false, \
4085}
4086#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004087
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004088/* can't be const, mac80211 writes to this */
4089static struct ieee80211_supported_band wl1271_band_2ghz = {
4090 .channels = wl1271_channels,
4091 .n_channels = ARRAY_SIZE(wl1271_channels),
4092 .bitrates = wl1271_rates,
4093 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004094 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004095};
4096
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004097/* 5 GHz data rates for WL1273 */
4098static struct ieee80211_rate wl1271_rates_5ghz[] = {
4099 { .bitrate = 60,
4100 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4101 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4102 { .bitrate = 90,
4103 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4104 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4105 { .bitrate = 120,
4106 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4107 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4108 { .bitrate = 180,
4109 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4110 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4111 { .bitrate = 240,
4112 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4113 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4114 { .bitrate = 360,
4115 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4116 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4117 { .bitrate = 480,
4118 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4119 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4120 { .bitrate = 540,
4121 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4122 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4123};
4124
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004125/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004126static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004127 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4128 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4129 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4130 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4131 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4132 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4133 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4134 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4135 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4136 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4137 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4138 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4139 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4140 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4141 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4142 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4143 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4144 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4145 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4146 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4147 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4148 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4149 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4150 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4151 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4152 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4153 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4154 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4155 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4156 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4157 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4158 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4159 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4160 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004161};
4162
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004163/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004164static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004165 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004166 7, /* CONF_HW_RXTX_RATE_MCS7 */
4167 6, /* CONF_HW_RXTX_RATE_MCS6 */
4168 5, /* CONF_HW_RXTX_RATE_MCS5 */
4169 4, /* CONF_HW_RXTX_RATE_MCS4 */
4170 3, /* CONF_HW_RXTX_RATE_MCS3 */
4171 2, /* CONF_HW_RXTX_RATE_MCS2 */
4172 1, /* CONF_HW_RXTX_RATE_MCS1 */
4173 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004174
4175 7, /* CONF_HW_RXTX_RATE_54 */
4176 6, /* CONF_HW_RXTX_RATE_48 */
4177 5, /* CONF_HW_RXTX_RATE_36 */
4178 4, /* CONF_HW_RXTX_RATE_24 */
4179
4180 /* TI-specific rate */
4181 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4182
4183 3, /* CONF_HW_RXTX_RATE_18 */
4184 2, /* CONF_HW_RXTX_RATE_12 */
4185 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4186 1, /* CONF_HW_RXTX_RATE_9 */
4187 0, /* CONF_HW_RXTX_RATE_6 */
4188 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4189 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4190 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4191};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004192
4193static struct ieee80211_supported_band wl1271_band_5ghz = {
4194 .channels = wl1271_channels_5ghz,
4195 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4196 .bitrates = wl1271_rates_5ghz,
4197 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004198 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004199};
4200
Tobias Klausera0ea9492010-05-20 10:38:11 +02004201static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004202 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4203 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4204};
4205
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004206static const struct ieee80211_ops wl1271_ops = {
4207 .start = wl1271_op_start,
4208 .stop = wl1271_op_stop,
4209 .add_interface = wl1271_op_add_interface,
4210 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004211#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004212 .suspend = wl1271_op_suspend,
4213 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004214#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004215 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004216 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004217 .configure_filter = wl1271_op_configure_filter,
4218 .tx = wl1271_op_tx,
4219 .set_key = wl1271_op_set_key,
4220 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004221 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004222 .sched_scan_start = wl1271_op_sched_scan_start,
4223 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004224 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004225 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004226 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004227 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004228 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004229 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004230 .sta_add = wl1271_op_sta_add,
4231 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004232 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004233 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004234 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004235};
4236
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004237
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004238u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004239{
4240 u8 idx;
4241
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004242 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004243
4244 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4245 wl1271_error("Illegal RX rate from HW: %d", rate);
4246 return 0;
4247 }
4248
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004249 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004250 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4251 wl1271_error("Unsupported RX rate from HW: %d", rate);
4252 return 0;
4253 }
4254
4255 return idx;
4256}
4257
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004258static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4259 struct device_attribute *attr,
4260 char *buf)
4261{
4262 struct wl1271 *wl = dev_get_drvdata(dev);
4263 ssize_t len;
4264
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004265 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004266
4267 mutex_lock(&wl->mutex);
4268 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4269 wl->sg_enabled);
4270 mutex_unlock(&wl->mutex);
4271
4272 return len;
4273
4274}
4275
4276static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4277 struct device_attribute *attr,
4278 const char *buf, size_t count)
4279{
4280 struct wl1271 *wl = dev_get_drvdata(dev);
4281 unsigned long res;
4282 int ret;
4283
Luciano Coelho6277ed62011-04-01 17:49:54 +03004284 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004285 if (ret < 0) {
4286 wl1271_warning("incorrect value written to bt_coex_mode");
4287 return count;
4288 }
4289
4290 mutex_lock(&wl->mutex);
4291
4292 res = !!res;
4293
4294 if (res == wl->sg_enabled)
4295 goto out;
4296
4297 wl->sg_enabled = res;
4298
4299 if (wl->state == WL1271_STATE_OFF)
4300 goto out;
4301
Ido Yariva6208652011-03-01 15:14:41 +02004302 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004303 if (ret < 0)
4304 goto out;
4305
4306 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4307 wl1271_ps_elp_sleep(wl);
4308
4309 out:
4310 mutex_unlock(&wl->mutex);
4311 return count;
4312}
4313
4314static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4315 wl1271_sysfs_show_bt_coex_state,
4316 wl1271_sysfs_store_bt_coex_state);
4317
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004318static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4319 struct device_attribute *attr,
4320 char *buf)
4321{
4322 struct wl1271 *wl = dev_get_drvdata(dev);
4323 ssize_t len;
4324
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004325 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004326
4327 mutex_lock(&wl->mutex);
4328 if (wl->hw_pg_ver >= 0)
4329 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4330 else
4331 len = snprintf(buf, len, "n/a\n");
4332 mutex_unlock(&wl->mutex);
4333
4334 return len;
4335}
4336
Gery Kahn6f07b722011-07-18 14:21:49 +03004337static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004338 wl1271_sysfs_show_hw_pg_ver, NULL);
4339
Ido Yariv95dac04f2011-06-06 14:57:06 +03004340static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4341 struct bin_attribute *bin_attr,
4342 char *buffer, loff_t pos, size_t count)
4343{
4344 struct device *dev = container_of(kobj, struct device, kobj);
4345 struct wl1271 *wl = dev_get_drvdata(dev);
4346 ssize_t len;
4347 int ret;
4348
4349 ret = mutex_lock_interruptible(&wl->mutex);
4350 if (ret < 0)
4351 return -ERESTARTSYS;
4352
4353 /* Let only one thread read the log at a time, blocking others */
4354 while (wl->fwlog_size == 0) {
4355 DEFINE_WAIT(wait);
4356
4357 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4358 &wait,
4359 TASK_INTERRUPTIBLE);
4360
4361 if (wl->fwlog_size != 0) {
4362 finish_wait(&wl->fwlog_waitq, &wait);
4363 break;
4364 }
4365
4366 mutex_unlock(&wl->mutex);
4367
4368 schedule();
4369 finish_wait(&wl->fwlog_waitq, &wait);
4370
4371 if (signal_pending(current))
4372 return -ERESTARTSYS;
4373
4374 ret = mutex_lock_interruptible(&wl->mutex);
4375 if (ret < 0)
4376 return -ERESTARTSYS;
4377 }
4378
4379 /* Check if the fwlog is still valid */
4380 if (wl->fwlog_size < 0) {
4381 mutex_unlock(&wl->mutex);
4382 return 0;
4383 }
4384
4385 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4386 len = min(count, (size_t)wl->fwlog_size);
4387 wl->fwlog_size -= len;
4388 memcpy(buffer, wl->fwlog, len);
4389
4390 /* Make room for new messages */
4391 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4392
4393 mutex_unlock(&wl->mutex);
4394
4395 return len;
4396}
4397
4398static struct bin_attribute fwlog_attr = {
4399 .attr = {.name = "fwlog", .mode = S_IRUSR},
4400 .read = wl1271_sysfs_read_fwlog,
4401};
4402
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004403int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004404{
4405 int ret;
4406
4407 if (wl->mac80211_registered)
4408 return 0;
4409
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004410 ret = wl1271_fetch_nvs(wl);
4411 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004412 /* NOTE: The wl->nvs->nvs element must be first, in
4413 * order to simplify the casting, we assume it is at
4414 * the beginning of the wl->nvs structure.
4415 */
4416 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004417
4418 wl->mac_addr[0] = nvs_ptr[11];
4419 wl->mac_addr[1] = nvs_ptr[10];
4420 wl->mac_addr[2] = nvs_ptr[6];
4421 wl->mac_addr[3] = nvs_ptr[5];
4422 wl->mac_addr[4] = nvs_ptr[4];
4423 wl->mac_addr[5] = nvs_ptr[3];
4424 }
4425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4427
4428 ret = ieee80211_register_hw(wl->hw);
4429 if (ret < 0) {
4430 wl1271_error("unable to register mac80211 hw: %d", ret);
4431 return ret;
4432 }
4433
4434 wl->mac80211_registered = true;
4435
Eliad Pellerd60080a2010-11-24 12:53:16 +02004436 wl1271_debugfs_init(wl);
4437
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004438 register_netdevice_notifier(&wl1271_dev_notifier);
4439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 wl1271_notice("loaded");
4441
4442 return 0;
4443}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004444EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004445
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004446void wl1271_unregister_hw(struct wl1271 *wl)
4447{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004448 if (wl->state == WL1271_STATE_PLT)
4449 __wl1271_plt_stop(wl);
4450
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004451 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004452 ieee80211_unregister_hw(wl->hw);
4453 wl->mac80211_registered = false;
4454
4455}
4456EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4457
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004458int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004459{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004460 static const u32 cipher_suites[] = {
4461 WLAN_CIPHER_SUITE_WEP40,
4462 WLAN_CIPHER_SUITE_WEP104,
4463 WLAN_CIPHER_SUITE_TKIP,
4464 WLAN_CIPHER_SUITE_CCMP,
4465 WL1271_CIPHER_SUITE_GEM,
4466 };
4467
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004468 /* The tx descriptor buffer and the TKIP space. */
4469 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4470 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471
4472 /* unit us */
4473 /* FIXME: find a proper value */
4474 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004475 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004476
4477 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004478 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004479 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004480 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004481 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004482 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004483 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004484 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004485 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004486 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004487
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004488 wl->hw->wiphy->cipher_suites = cipher_suites;
4489 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4490
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004491 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004492 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004493 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelhof9520792011-08-23 18:34:44 +03004494 wl->hw->wiphy->max_sched_scan_ssids = 8;
Guy Eilamea559b42010-12-09 16:54:59 +02004495 /*
4496 * Maximum length of elements in scanning probe request templates
4497 * should be the maximum length possible for a template, without
4498 * the IEEE80211 header of the template
4499 */
Eliad Peller154037d2011-08-14 13:17:12 +03004500 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004501 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004502
Luciano Coelho4a31c112011-03-21 23:16:14 +02004503 /* make sure all our channels fit in the scanned_ch bitmask */
4504 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4505 ARRAY_SIZE(wl1271_channels_5ghz) >
4506 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004507 /*
4508 * We keep local copies of the band structs because we need to
4509 * modify them on a per-device basis.
4510 */
4511 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4512 sizeof(wl1271_band_2ghz));
4513 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4514 sizeof(wl1271_band_5ghz));
4515
4516 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4517 &wl->bands[IEEE80211_BAND_2GHZ];
4518 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4519 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004520
Kalle Valo12bd8942010-03-18 12:26:33 +02004521 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004522 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004523
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004524 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4525
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004526 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004527
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004528 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4529
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004530 wl->hw->max_rx_aggregation_subframes = 8;
4531
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004532 return 0;
4533}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004534EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004536#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004537
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004538struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004540 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004541 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004542 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004543 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004544 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004545
4546 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4547 if (!hw) {
4548 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004549 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004550 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004551 }
4552
Julia Lawall929ebd32010-05-15 23:16:39 +02004553 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004554 if (!plat_dev) {
4555 wl1271_error("could not allocate platform_device");
4556 ret = -ENOMEM;
4557 goto err_plat_alloc;
4558 }
4559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004560 wl = hw->priv;
4561 memset(wl, 0, sizeof(*wl));
4562
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004563 INIT_LIST_HEAD(&wl->list);
4564
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004565 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004566 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004567
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004568 for (i = 0; i < NUM_TX_QUEUES; i++)
4569 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004570
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004571 for (i = 0; i < NUM_TX_QUEUES; i++)
4572 for (j = 0; j < AP_MAX_LINKS; j++)
4573 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4574
Ido Yariva6208652011-03-01 15:14:41 +02004575 skb_queue_head_init(&wl->deferred_rx_queue);
4576 skb_queue_head_init(&wl->deferred_tx_queue);
4577
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004578 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004579 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004580 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004581 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4582 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4583 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004584 INIT_WORK(&wl->rx_streaming_enable_work,
4585 wl1271_rx_streaming_enable_work);
4586 INIT_WORK(&wl->rx_streaming_disable_work,
4587 wl1271_rx_streaming_disable_work);
4588
Eliad Peller92ef8962011-06-07 12:50:46 +03004589 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4590 if (!wl->freezable_wq) {
4591 ret = -ENOMEM;
4592 goto err_hw;
4593 }
4594
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004595 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004596 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004597 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004598 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004599 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004600 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004601 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004602 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004603 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004604 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004605 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004606 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004607 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004608 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004609 wl->bss_type = MAX_BSS_TYPE;
4610 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004611 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004612 wl->ap_ps_map = 0;
4613 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004614 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004615 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004616 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004617 wl->tx_security_seq = 0;
4618 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004619 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004620 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004621 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004622 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004623 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4624 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004625 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004626 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4627 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004628 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4629 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004630 wl->fwlog_size = 0;
4631 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004632
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004633 /* The system link is always allocated */
4634 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4635
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004636 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004637 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004638 wl->tx_frames[i] = NULL;
4639
4640 spin_lock_init(&wl->wl_lock);
4641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004642 wl->state = WL1271_STATE_OFF;
4643 mutex_init(&wl->mutex);
4644
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004645 /* Apply default driver configuration. */
4646 wl1271_conf_init(wl);
4647
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004648 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4649 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4650 if (!wl->aggr_buf) {
4651 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004652 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004653 }
4654
Ido Yariv990f5de2011-03-31 10:06:59 +02004655 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4656 if (!wl->dummy_packet) {
4657 ret = -ENOMEM;
4658 goto err_aggr;
4659 }
4660
Ido Yariv95dac04f2011-06-06 14:57:06 +03004661 /* Allocate one page for the FW log */
4662 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4663 if (!wl->fwlog) {
4664 ret = -ENOMEM;
4665 goto err_dummy_packet;
4666 }
4667
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004668 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004669 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004670 if (ret) {
4671 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004672 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004673 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004674 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004675
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004676 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004677 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004678 if (ret < 0) {
4679 wl1271_error("failed to create sysfs file bt_coex_state");
4680 goto err_platform;
4681 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004682
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004683 /* Create sysfs file to get HW PG version */
4684 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4685 if (ret < 0) {
4686 wl1271_error("failed to create sysfs file hw_pg_ver");
4687 goto err_bt_coex_state;
4688 }
4689
Ido Yariv95dac04f2011-06-06 14:57:06 +03004690 /* Create sysfs file for the FW log */
4691 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4692 if (ret < 0) {
4693 wl1271_error("failed to create sysfs file fwlog");
4694 goto err_hw_pg_ver;
4695 }
4696
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004697 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004698
Ido Yariv95dac04f2011-06-06 14:57:06 +03004699err_hw_pg_ver:
4700 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4701
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004702err_bt_coex_state:
4703 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4704
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004705err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004706 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004707
Ido Yariv95dac04f2011-06-06 14:57:06 +03004708err_fwlog:
4709 free_page((unsigned long)wl->fwlog);
4710
Ido Yariv990f5de2011-03-31 10:06:59 +02004711err_dummy_packet:
4712 dev_kfree_skb(wl->dummy_packet);
4713
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004714err_aggr:
4715 free_pages((unsigned long)wl->aggr_buf, order);
4716
Eliad Peller92ef8962011-06-07 12:50:46 +03004717err_wq:
4718 destroy_workqueue(wl->freezable_wq);
4719
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004720err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004721 wl1271_debugfs_exit(wl);
4722 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004723
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004724err_plat_alloc:
4725 ieee80211_free_hw(hw);
4726
4727err_hw_alloc:
4728
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004729 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004730}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004731EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004732
4733int wl1271_free_hw(struct wl1271 *wl)
4734{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004735 /* Unblock any fwlog readers */
4736 mutex_lock(&wl->mutex);
4737 wl->fwlog_size = -1;
4738 wake_up_interruptible_all(&wl->fwlog_waitq);
4739 mutex_unlock(&wl->mutex);
4740
4741 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004742
4743 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4744
4745 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004746 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004747 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004748 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004749 free_pages((unsigned long)wl->aggr_buf,
4750 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004751 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004752
4753 wl1271_debugfs_exit(wl);
4754
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004755 vfree(wl->fw);
4756 wl->fw = NULL;
4757 kfree(wl->nvs);
4758 wl->nvs = NULL;
4759
4760 kfree(wl->fw_status);
4761 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004762 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004763
4764 ieee80211_free_hw(wl->hw);
4765
4766 return 0;
4767}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004768EXPORT_SYMBOL_GPL(wl1271_free_hw);
4769
Guy Eilam491bbd62011-01-12 10:33:29 +01004770u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004771EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004772module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004773MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4774
Ido Yariv95dac04f2011-06-06 14:57:06 +03004775module_param_named(fwlog, fwlog_param, charp, 0);
4776MODULE_PARM_DESC(keymap,
4777 "FW logger options: continuous, ondemand, dbgpins or disable");
4778
Eliad Peller2a5bff02011-08-25 18:10:59 +03004779module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
4780MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
4781
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004782MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004783MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004784MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");