blob: 0fa3a2281ddb347184550371a7a0d3397df06207 [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,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200239 .psm_entry_retries = 5,
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;
365
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300366static void __wl1271_op_remove_interface(struct wl1271 *wl,
367 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200368static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200369
370
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200371static void wl1271_device_release(struct device *dev)
372{
373
374}
375
376static struct platform_device wl1271_device = {
377 .name = "wl1271",
378 .id = -1,
379
380 /* device model insists to have a release function */
381 .dev = {
382 .release = wl1271_device_release,
383 },
384};
385
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200386static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300387static LIST_HEAD(wl_list);
388
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300389static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
390{
391 int ret;
392 if (operstate != IF_OPER_UP)
393 return 0;
394
395 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
396 return 0;
397
Eliad Pellerb67476e2011-08-14 13:17:23 +0300398 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 if (ret < 0)
400 return ret;
401
Eliad Peller251c1772011-08-14 13:17:17 +0300402 wl12xx_croc(wl, wl->role_id);
403
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300404 wl1271_info("Association completed.");
405 return 0;
406}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300407static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
408 void *arg)
409{
410 struct net_device *dev = arg;
411 struct wireless_dev *wdev;
412 struct wiphy *wiphy;
413 struct ieee80211_hw *hw;
414 struct wl1271 *wl;
415 struct wl1271 *wl_temp;
416 int ret = 0;
417
418 /* Check that this notification is for us. */
419 if (what != NETDEV_CHANGE)
420 return NOTIFY_DONE;
421
422 wdev = dev->ieee80211_ptr;
423 if (wdev == NULL)
424 return NOTIFY_DONE;
425
426 wiphy = wdev->wiphy;
427 if (wiphy == NULL)
428 return NOTIFY_DONE;
429
430 hw = wiphy_priv(wiphy);
431 if (hw == NULL)
432 return NOTIFY_DONE;
433
434 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200435 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300436 list_for_each_entry(wl, &wl_list, list) {
437 if (wl == wl_temp)
438 break;
439 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200440 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300441 if (wl != wl_temp)
442 return NOTIFY_DONE;
443
444 mutex_lock(&wl->mutex);
445
446 if (wl->state == WL1271_STATE_OFF)
447 goto out;
448
449 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
450 goto out;
451
Ido Yariva6208652011-03-01 15:14:41 +0200452 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 if (ret < 0)
454 goto out;
455
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300456 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300457
458 wl1271_ps_elp_sleep(wl);
459
460out:
461 mutex_unlock(&wl->mutex);
462
463 return NOTIFY_OK;
464}
465
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100466static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200467 struct regulatory_request *request)
468{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100469 struct ieee80211_supported_band *band;
470 struct ieee80211_channel *ch;
471 int i;
472
473 band = wiphy->bands[IEEE80211_BAND_5GHZ];
474 for (i = 0; i < band->n_channels; i++) {
475 ch = &band->channels[i];
476 if (ch->flags & IEEE80211_CHAN_DISABLED)
477 continue;
478
479 if (ch->flags & IEEE80211_CHAN_RADAR)
480 ch->flags |= IEEE80211_CHAN_NO_IBSS |
481 IEEE80211_CHAN_PASSIVE_SCAN;
482
483 }
484
485 return 0;
486}
487
Eliad Peller77ddaa12011-05-15 11:10:29 +0300488static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
489{
490 int ret = 0;
491
492 /* we should hold wl->mutex */
493 ret = wl1271_acx_ps_rx_streaming(wl, enable);
494 if (ret < 0)
495 goto out;
496
497 if (enable)
498 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
499 else
500 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
501out:
502 return ret;
503}
504
505/*
506 * this function is being called when the rx_streaming interval
507 * has beed changed or rx_streaming should be disabled
508 */
509int wl1271_recalc_rx_streaming(struct wl1271 *wl)
510{
511 int ret = 0;
512 int period = wl->conf.rx_streaming.interval;
513
514 /* don't reconfigure if rx_streaming is disabled */
515 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
516 goto out;
517
518 /* reconfigure/disable according to new streaming_period */
519 if (period &&
520 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
521 (wl->conf.rx_streaming.always ||
522 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
523 ret = wl1271_set_rx_streaming(wl, true);
524 else {
525 ret = wl1271_set_rx_streaming(wl, false);
526 /* don't cancel_work_sync since we might deadlock */
527 del_timer_sync(&wl->rx_streaming_timer);
528 }
529out:
530 return ret;
531}
532
533static void wl1271_rx_streaming_enable_work(struct work_struct *work)
534{
535 int ret;
536 struct wl1271 *wl =
537 container_of(work, struct wl1271, rx_streaming_enable_work);
538
539 mutex_lock(&wl->mutex);
540
541 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
542 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
543 (!wl->conf.rx_streaming.always &&
544 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
545 goto out;
546
547 if (!wl->conf.rx_streaming.interval)
548 goto out;
549
550 ret = wl1271_ps_elp_wakeup(wl);
551 if (ret < 0)
552 goto out;
553
554 ret = wl1271_set_rx_streaming(wl, true);
555 if (ret < 0)
556 goto out_sleep;
557
558 /* stop it after some time of inactivity */
559 mod_timer(&wl->rx_streaming_timer,
560 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
561
562out_sleep:
563 wl1271_ps_elp_sleep(wl);
564out:
565 mutex_unlock(&wl->mutex);
566}
567
568static void wl1271_rx_streaming_disable_work(struct work_struct *work)
569{
570 int ret;
571 struct wl1271 *wl =
572 container_of(work, struct wl1271, rx_streaming_disable_work);
573
574 mutex_lock(&wl->mutex);
575
576 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
577 goto out;
578
579 ret = wl1271_ps_elp_wakeup(wl);
580 if (ret < 0)
581 goto out;
582
583 ret = wl1271_set_rx_streaming(wl, false);
584 if (ret)
585 goto out_sleep;
586
587out_sleep:
588 wl1271_ps_elp_sleep(wl);
589out:
590 mutex_unlock(&wl->mutex);
591}
592
593static void wl1271_rx_streaming_timer(unsigned long data)
594{
595 struct wl1271 *wl = (struct wl1271 *)data;
596 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
597}
598
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300599static void wl1271_conf_init(struct wl1271 *wl)
600{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300601
602 /*
603 * This function applies the default configuration to the driver. This
604 * function is invoked upon driver load (spi probe.)
605 *
606 * The configuration is stored in a run-time structure in order to
607 * facilitate for run-time adjustment of any of the parameters. Making
608 * changes to the configuration structure will apply the new values on
609 * the next interface up (wl1271_op_start.)
610 */
611
612 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300613 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
Ido Yariv95dac04f2011-06-06 14:57:06 +0300615 /* Adjust settings according to optional module parameters */
616 if (fwlog_param) {
617 if (!strcmp(fwlog_param, "continuous")) {
618 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
619 } else if (!strcmp(fwlog_param, "ondemand")) {
620 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
621 } else if (!strcmp(fwlog_param, "dbgpins")) {
622 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
623 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
624 } else if (!strcmp(fwlog_param, "disable")) {
625 wl->conf.fwlog.mem_blocks = 0;
626 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
627 } else {
628 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
629 }
630 }
631}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300632
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633static int wl1271_plt_init(struct wl1271 *wl)
634{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200635 struct conf_tx_ac_category *conf_ac;
636 struct conf_tx_tid *conf_tid;
637 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638
Shahar Levi49d750ca2011-03-06 16:32:09 +0200639 if (wl->chip.id == CHIP_ID_1283_PG20)
640 ret = wl128x_cmd_general_parms(wl);
641 else
642 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200643 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200644 return ret;
645
Shahar Levi49d750ca2011-03-06 16:32:09 +0200646 if (wl->chip.id == CHIP_ID_1283_PG20)
647 ret = wl128x_cmd_radio_parms(wl);
648 else
649 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200650 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200651 return ret;
652
Shahar Levi49d750ca2011-03-06 16:32:09 +0200653 if (wl->chip.id != CHIP_ID_1283_PG20) {
654 ret = wl1271_cmd_ext_radio_parms(wl);
655 if (ret < 0)
656 return ret;
657 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200658 if (ret < 0)
659 return ret;
660
Shahar Levi48a61472011-03-06 16:32:08 +0200661 /* Chip-specific initializations */
662 ret = wl1271_chip_specific_init(wl);
663 if (ret < 0)
664 return ret;
665
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200666 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200667 if (ret < 0)
668 return ret;
669
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 ret = wl1271_acx_init_mem_config(wl);
671 if (ret < 0)
672 return ret;
673
Luciano Coelho12419cc2010-02-18 13:25:44 +0200674 /* PHY layer config */
675 ret = wl1271_init_phy_config(wl);
676 if (ret < 0)
677 goto out_free_memmap;
678
679 ret = wl1271_acx_dco_itrim_params(wl);
680 if (ret < 0)
681 goto out_free_memmap;
682
683 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200684 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200685 if (ret < 0)
686 goto out_free_memmap;
687
688 /* Bluetooth WLAN coexistence */
689 ret = wl1271_init_pta(wl);
690 if (ret < 0)
691 goto out_free_memmap;
692
Shahar Leviff868432011-04-11 15:41:46 +0300693 /* FM WLAN coexistence */
694 ret = wl1271_acx_fm_coex(wl);
695 if (ret < 0)
696 goto out_free_memmap;
697
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 /* Energy detection */
699 ret = wl1271_init_energy_detection(wl);
700 if (ret < 0)
701 goto out_free_memmap;
702
Eliad Peller7f0979882011-08-14 13:17:06 +0300703 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600704 if (ret < 0)
705 goto out_free_memmap;
706
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100708 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200709 if (ret < 0)
710 goto out_free_memmap;
711
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200712 /* Default TID/AC configuration */
713 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200714 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200715 conf_ac = &wl->conf.tx.ac_conf[i];
716 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
717 conf_ac->cw_max, conf_ac->aifsn,
718 conf_ac->tx_op_limit);
719 if (ret < 0)
720 goto out_free_memmap;
721
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 conf_tid = &wl->conf.tx.tid_conf[i];
723 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
724 conf_tid->channel_type,
725 conf_tid->tsid,
726 conf_tid->ps_scheme,
727 conf_tid->ack_policy,
728 conf_tid->apsd_conf[0],
729 conf_tid->apsd_conf[1]);
730 if (ret < 0)
731 goto out_free_memmap;
732 }
733
Luciano Coelho12419cc2010-02-18 13:25:44 +0200734 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200735 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200737 goto out_free_memmap;
738
739 /* Configure for CAM power saving (ie. always active) */
740 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
741 if (ret < 0)
742 goto out_free_memmap;
743
744 /* configure PM */
745 ret = wl1271_acx_pm_config(wl);
746 if (ret < 0)
747 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750
751 out_free_memmap:
752 kfree(wl->target_mem_map);
753 wl->target_mem_map = NULL;
754
755 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300756}
757
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300758#if 0
Arik Nemtsovb622d992011-02-23 00:22:31 +0200759static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
760{
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
771 * blocks in FW or if the STA is awake.
772 */
773 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
774 wl1271_ps_link_end(wl, hlid);
775
776 /* Start high-level PS if the STA is asleep with enough blocks in FW */
777 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
778 wl1271_ps_link_start(wl, hlid, true);
779}
780
781static void wl1271_irq_update_links_status(struct wl1271 *wl,
782 struct wl1271_fw_ap_status *status)
783{
784 u32 cur_fw_ps_map;
785 u8 hlid;
786
787 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
788 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
789 wl1271_debug(DEBUG_PSM,
790 "link ps prev 0x%x cur 0x%x changed 0x%x",
791 wl->ap_fw_ps_map, cur_fw_ps_map,
792 wl->ap_fw_ps_map ^ cur_fw_ps_map);
793
794 wl->ap_fw_ps_map = cur_fw_ps_map;
795 }
796
797 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
798 u8 cnt = status->tx_lnk_free_blks[hlid] -
799 wl->links[hlid].prev_freed_blks;
800
801 wl->links[hlid].prev_freed_blks =
802 status->tx_lnk_free_blks[hlid];
803 wl->links[hlid].allocated_blks -= cnt;
804
805 wl1271_irq_ps_regulate_link(wl, hlid,
806 wl->links[hlid].allocated_blks);
807 }
808}
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300809#endif
Arik Nemtsovb622d992011-02-23 00:22:31 +0200810
Eliad Peller4d56ad92011-08-14 13:17:05 +0300811static void wl12xx_fw_status(struct wl1271 *wl,
812 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300813{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200814 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200815 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300816 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300817 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818
Eliad Peller4d56ad92011-08-14 13:17:05 +0300819 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
822 "drv_rx_counter = %d, tx_results_counter = %d)",
823 status->intr,
824 status->fw_rx_counter,
825 status->drv_rx_counter,
826 status->tx_results_counter);
827
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300828 for (i = 0; i < NUM_TX_QUEUES; i++) {
829 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300830 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300831 (status->tx_released_pkts[i] -
832 wl->tx_pkts_freed[i]) & 0xff;
833
834 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
835 }
836
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300837 /* prevent wrap-around in total blocks counter */
838 if (likely(wl->tx_blocks_freed <=
839 le32_to_cpu(status->total_released_blks)))
840 freed_blocks = le32_to_cpu(status->total_released_blks) -
841 wl->tx_blocks_freed;
842 else
843 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
844 le32_to_cpu(status->total_released_blks);
845
Eliad Peller4d56ad92011-08-14 13:17:05 +0300846 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200847
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300848 wl->tx_allocated_blocks -= freed_blocks;
849
Eliad Peller4d56ad92011-08-14 13:17:05 +0300850 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200851
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852 /*
853 * The FW might change the total number of TX memblocks before
854 * we get a notification about blocks being released. Thus, the
855 * available blocks calculation might yield a temporary result
856 * which is lower than the actual available blocks. Keeping in
857 * mind that only blocks that were allocated can be moved from
858 * TX to RX, tx_blocks_available should never decrease here.
859 */
860 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
861 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862
Ido Yariva5225502010-10-12 14:49:10 +0200863 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200864 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200865 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866
Eliad Peller4d56ad92011-08-14 13:17:05 +0300867 /* for AP update num of allocated TX blocks per link and ps status */
868 if (wl->bss_type == BSS_TYPE_AP_BSS) {
869#if 0
870 wl1271_irq_update_links_status(wl, status);
871#endif
872 }
873
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200875 getnstimeofday(&ts);
876 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
877 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878}
879
Ido Yariva6208652011-03-01 15:14:41 +0200880static void wl1271_flush_deferred_work(struct wl1271 *wl)
881{
882 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200883
Ido Yariva6208652011-03-01 15:14:41 +0200884 /* Pass all received frames to the network stack */
885 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
886 ieee80211_rx_ni(wl->hw, skb);
887
888 /* Return sent skbs to the network stack */
889 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300890 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200891}
892
893static void wl1271_netstack_work(struct work_struct *work)
894{
895 struct wl1271 *wl =
896 container_of(work, struct wl1271, netstack_work);
897
898 do {
899 wl1271_flush_deferred_work(wl);
900 } while (skb_queue_len(&wl->deferred_rx_queue));
901}
902
903#define WL1271_IRQ_MAX_LOOPS 256
904
905irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300906{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300908 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200910 struct wl1271 *wl = (struct wl1271 *)cookie;
911 bool done = false;
912 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200913 unsigned long flags;
914
915 /* TX might be handled here, avoid redundant work */
916 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
917 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918
Ido Yariv341b7cd2011-03-31 10:07:01 +0200919 /*
920 * In case edge triggered interrupt must be used, we cannot iterate
921 * more than once without introducing race conditions with the hardirq.
922 */
923 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
924 loopcount = 1;
925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 mutex_lock(&wl->mutex);
927
928 wl1271_debug(DEBUG_IRQ, "IRQ work");
929
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200930 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 goto out;
932
Ido Yariva6208652011-03-01 15:14:41 +0200933 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 if (ret < 0)
935 goto out;
936
Ido Yariva6208652011-03-01 15:14:41 +0200937 while (!done && loopcount--) {
938 /*
939 * In order to avoid a race with the hardirq, clear the flag
940 * before acknowledging the chip. Since the mutex is held,
941 * wl1271_ps_elp_wakeup cannot be called concurrently.
942 */
943 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
944 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200945
Eliad Peller4d56ad92011-08-14 13:17:05 +0300946 wl12xx_fw_status(wl, wl->fw_status);
947 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200948 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200949 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200950 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200951 continue;
952 }
953
Eliad Pellerccc83b02010-10-27 14:09:57 +0200954 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
955 wl1271_error("watchdog interrupt received! "
956 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300957 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200958
959 /* restarting the chip. ignore any other interrupt. */
960 goto out;
961 }
962
Ido Yariva6208652011-03-01 15:14:41 +0200963 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200964 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
965
Eliad Peller4d56ad92011-08-14 13:17:05 +0300966 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200967
Ido Yariva5225502010-10-12 14:49:10 +0200968 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200969 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200970 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300971 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200972 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200973 /*
974 * In order to avoid starvation of the TX path,
975 * call the work function directly.
976 */
977 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200978 } else {
979 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200980 }
981
Ido Yariv8aad2462011-03-01 15:14:38 +0200982 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300983 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200984 (wl->tx_results_count & 0xff))
985 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200986
987 /* Make sure the deferred queues don't get too long */
988 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
989 skb_queue_len(&wl->deferred_rx_queue);
990 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
991 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200992 }
993
994 if (intr & WL1271_ACX_INTR_EVENT_A) {
995 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
996 wl1271_event_handle(wl, 0);
997 }
998
999 if (intr & WL1271_ACX_INTR_EVENT_B) {
1000 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1001 wl1271_event_handle(wl, 1);
1002 }
1003
1004 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1005 wl1271_debug(DEBUG_IRQ,
1006 "WL1271_ACX_INTR_INIT_COMPLETE");
1007
1008 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1009 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 }
1011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 wl1271_ps_elp_sleep(wl);
1013
1014out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001015 spin_lock_irqsave(&wl->wl_lock, flags);
1016 /* In case TX was not handled here, queue TX work */
1017 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1018 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001019 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001020 ieee80211_queue_work(wl->hw, &wl->tx_work);
1021 spin_unlock_irqrestore(&wl->wl_lock, flags);
1022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001024
1025 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026}
Ido Yariva6208652011-03-01 15:14:41 +02001027EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029static int wl1271_fetch_firmware(struct wl1271 *wl)
1030{
1031 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001032 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 int ret;
1034
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001035 if (wl->chip.id == CHIP_ID_1283_PG20)
1036 fw_name = WL128X_FW_NAME;
1037 else
1038 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001039
1040 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1041
1042 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 if (ret < 0) {
1045 wl1271_error("could not get firmware: %d", ret);
1046 return ret;
1047 }
1048
1049 if (fw->size % 4) {
1050 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1051 fw->size);
1052 ret = -EILSEQ;
1053 goto out;
1054 }
1055
Arik Nemtsov166d5042010-10-16 21:44:57 +02001056 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001058 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059
1060 if (!wl->fw) {
1061 wl1271_error("could not allocate memory for the firmware");
1062 ret = -ENOMEM;
1063 goto out;
1064 }
1065
1066 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067 ret = 0;
1068
1069out:
1070 release_firmware(fw);
1071
1072 return ret;
1073}
1074
1075static int wl1271_fetch_nvs(struct wl1271 *wl)
1076{
1077 const struct firmware *fw;
1078 int ret;
1079
Shahar Levi5aa42342011-03-06 16:32:07 +02001080 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
1082 if (ret < 0) {
1083 wl1271_error("could not get nvs file: %d", ret);
1084 return ret;
1085 }
1086
Shahar Levibc765bf2011-03-06 16:32:10 +02001087 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088
1089 if (!wl->nvs) {
1090 wl1271_error("could not allocate memory for the nvs file");
1091 ret = -ENOMEM;
1092 goto out;
1093 }
1094
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001095 wl->nvs_len = fw->size;
1096
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097out:
1098 release_firmware(fw);
1099
1100 return ret;
1101}
1102
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001103void wl12xx_queue_recovery_work(struct wl1271 *wl)
1104{
1105 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1106 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1107}
1108
Ido Yariv95dac04f2011-06-06 14:57:06 +03001109size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1110{
1111 size_t len = 0;
1112
1113 /* The FW log is a length-value list, find where the log end */
1114 while (len < maxlen) {
1115 if (memblock[len] == 0)
1116 break;
1117 if (len + memblock[len] + 1 > maxlen)
1118 break;
1119 len += memblock[len] + 1;
1120 }
1121
1122 /* Make sure we have enough room */
1123 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1124
1125 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1126 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1127 wl->fwlog_size += len;
1128
1129 return len;
1130}
1131
1132static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1133{
1134 u32 addr;
1135 u32 first_addr;
1136 u8 *block;
1137
1138 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1139 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1140 (wl->conf.fwlog.mem_blocks == 0))
1141 return;
1142
1143 wl1271_info("Reading FW panic log");
1144
1145 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1146 if (!block)
1147 return;
1148
1149 /*
1150 * Make sure the chip is awake and the logger isn't active.
1151 * This might fail if the firmware hanged.
1152 */
1153 if (!wl1271_ps_elp_wakeup(wl))
1154 wl12xx_cmd_stop_fwlog(wl);
1155
1156 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001157 wl12xx_fw_status(wl, wl->fw_status);
1158 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001159 if (!first_addr)
1160 goto out;
1161
1162 /* Traverse the memory blocks linked list */
1163 addr = first_addr;
1164 do {
1165 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1166 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1167 false);
1168
1169 /*
1170 * Memory blocks are linked to one another. The first 4 bytes
1171 * of each memory block hold the hardware address of the next
1172 * one. The last memory block points to the first one.
1173 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001174 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001175 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1176 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1177 break;
1178 } while (addr && (addr != first_addr));
1179
1180 wake_up_interruptible(&wl->fwlog_waitq);
1181
1182out:
1183 kfree(block);
1184}
1185
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001186static void wl1271_recovery_work(struct work_struct *work)
1187{
1188 struct wl1271 *wl =
1189 container_of(work, struct wl1271, recovery_work);
1190
1191 mutex_lock(&wl->mutex);
1192
1193 if (wl->state != WL1271_STATE_ON)
1194 goto out;
1195
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001196 /* Avoid a recursive recovery */
1197 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1198
Ido Yariv95dac04f2011-06-06 14:57:06 +03001199 wl12xx_read_fwlog_panic(wl);
1200
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001201 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1202 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001203
Oz Krakowskib992c682011-06-26 10:36:02 +03001204 /*
1205 * Advance security sequence number to overcome potential progress
1206 * in the firmware during recovery. This doens't hurt if the network is
1207 * not encrypted.
1208 */
1209 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1210 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1211 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1212
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001213 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1214 ieee80211_connection_loss(wl->vif);
1215
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001216 /* Prevent spurious TX during FW restart */
1217 ieee80211_stop_queues(wl->hw);
1218
Luciano Coelho33c2c062011-05-10 14:46:02 +03001219 if (wl->sched_scanning) {
1220 ieee80211_sched_scan_stopped(wl->hw);
1221 wl->sched_scanning = false;
1222 }
1223
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001224 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001225 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001226
1227 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1228
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001229 ieee80211_restart_hw(wl->hw);
1230
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001231 /*
1232 * Its safe to enable TX now - the queues are stopped after a request
1233 * to restart the HW.
1234 */
1235 ieee80211_wake_queues(wl->hw);
1236
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001237out:
1238 mutex_unlock(&wl->mutex);
1239}
1240
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241static void wl1271_fw_wakeup(struct wl1271 *wl)
1242{
1243 u32 elp_reg;
1244
1245 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001246 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247}
1248
1249static int wl1271_setup(struct wl1271 *wl)
1250{
1251 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1252 if (!wl->fw_status)
1253 return -ENOMEM;
1254
1255 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1256 if (!wl->tx_res_if) {
1257 kfree(wl->fw_status);
1258 return -ENOMEM;
1259 }
1260
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261 return 0;
1262}
1263
1264static int wl1271_chip_wakeup(struct wl1271 *wl)
1265{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001266 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267 int ret = 0;
1268
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001269 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001270 ret = wl1271_power_on(wl);
1271 if (ret < 0)
1272 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001274 wl1271_io_reset(wl);
1275 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276
1277 /* We don't need a real memory partition here, because we only want
1278 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001279 memset(&partition, 0, sizeof(partition));
1280 partition.reg.start = REGISTERS_BASE;
1281 partition.reg.size = REGISTERS_DOWN_SIZE;
1282 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
1284 /* ELP module wake up */
1285 wl1271_fw_wakeup(wl);
1286
1287 /* whal_FwCtrl_BootSm() */
1288
1289 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001290 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291
1292 /* 1. check if chip id is valid */
1293
1294 switch (wl->chip.id) {
1295 case CHIP_ID_1271_PG10:
1296 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001301 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 break;
1303 case CHIP_ID_1271_PG20:
1304 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1305 wl->chip.id);
1306
Shahar Levi0c005042011-06-12 10:34:43 +03001307 /*
1308 * 'end-of-transaction flag' and 'LPD mode flag'
1309 * should be set in wl127x AP mode only
1310 */
Shahar Levi564f5952011-04-04 10:20:39 +03001311 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001312 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1313 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001314
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 ret = wl1271_setup(wl);
1316 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001317 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001319 case CHIP_ID_1283_PG20:
1320 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
1325 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001326
Ido Yariv0da13da2011-03-31 10:06:58 +02001327 if (wl1271_set_block_size(wl))
1328 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001329 break;
1330 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001332 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001334 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335 }
1336
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001337 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 ret = wl1271_fetch_firmware(wl);
1339 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001340 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 }
1342
1343 /* No NVS from netlink, try to get it from the filesystem */
1344 if (wl->nvs == NULL) {
1345 ret = wl1271_fetch_nvs(wl);
1346 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001347 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 }
1349
1350out:
1351 return ret;
1352}
1353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354int wl1271_plt_start(struct wl1271 *wl)
1355{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001357 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 int ret;
1359
1360 mutex_lock(&wl->mutex);
1361
1362 wl1271_notice("power up");
1363
1364 if (wl->state != WL1271_STATE_OFF) {
1365 wl1271_error("cannot go into PLT state because not "
1366 "in off state: %d", wl->state);
1367 ret = -EBUSY;
1368 goto out;
1369 }
1370
Arik Nemtsov166d5042010-10-16 21:44:57 +02001371 wl->bss_type = BSS_TYPE_STA_BSS;
1372
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001373 while (retries) {
1374 retries--;
1375 ret = wl1271_chip_wakeup(wl);
1376 if (ret < 0)
1377 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001379 ret = wl1271_boot(wl);
1380 if (ret < 0)
1381 goto power_off;
1382
1383 ret = wl1271_plt_init(wl);
1384 if (ret < 0)
1385 goto irq_disable;
1386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 wl->state = WL1271_STATE_PLT;
1388 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001389 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001390
Gery Kahn6f07b722011-07-18 14:21:49 +03001391 /* update hw/fw version info in wiphy struct */
1392 wiphy->hw_version = wl->chip.id;
1393 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1394 sizeof(wiphy->fw_version));
1395
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396 goto out;
1397
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001398irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001399 mutex_unlock(&wl->mutex);
1400 /* Unlocking the mutex in the middle of handling is
1401 inherently unsafe. In this case we deem it safe to do,
1402 because we need to let any possibly pending IRQ out of
1403 the system (and while we are WL1271_STATE_OFF the IRQ
1404 work function will not do anything.) Also, any other
1405 possible concurrent operations will fail due to the
1406 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001407 wl1271_disable_interrupts(wl);
1408 wl1271_flush_deferred_work(wl);
1409 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001410 mutex_lock(&wl->mutex);
1411power_off:
1412 wl1271_power_off(wl);
1413 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001415 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1416 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417out:
1418 mutex_unlock(&wl->mutex);
1419
1420 return ret;
1421}
1422
Luciano Coelho4623ec72011-03-21 19:26:41 +02001423static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424{
1425 int ret = 0;
1426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427 wl1271_notice("power down");
1428
1429 if (wl->state != WL1271_STATE_PLT) {
1430 wl1271_error("cannot power down because not in PLT "
1431 "state: %d", wl->state);
1432 ret = -EBUSY;
1433 goto out;
1434 }
1435
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 wl1271_power_off(wl);
1437
1438 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001439 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001442 wl1271_disable_interrupts(wl);
1443 wl1271_flush_deferred_work(wl);
1444 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001445 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001446 mutex_lock(&wl->mutex);
1447out:
1448 return ret;
1449}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001450
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001451int wl1271_plt_stop(struct wl1271 *wl)
1452{
1453 int ret;
1454
1455 mutex_lock(&wl->mutex);
1456 ret = __wl1271_plt_stop(wl);
1457 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 return ret;
1459}
1460
Johannes Berg7bb45682011-02-24 14:42:06 +01001461static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462{
1463 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001464 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001465 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001466 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001468 mapping = skb_get_queue_mapping(skb);
1469 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001470
1471 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001472 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001473
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001474 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001475
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001476 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001477
1478 /*
1479 * The workqueue is slow to process the tx_queue and we need stop
1480 * the queue here, otherwise the queue will get too long.
1481 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001482 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001483 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1484 ieee80211_stop_queue(wl->hw, mapping);
1485 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001486 }
1487
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 Nemtsova8c0ddb2011-02-23 00:22:26 +02001490 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1491 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1492 } else {
1493 skb_queue_tail(&wl->tx_queue[q], skb);
1494 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495
1496 /*
1497 * The chip specific setup must run before the first TX packet -
1498 * before that, the tx_work will not be initialized!
1499 */
1500
Ido Yarivb07d4032011-03-01 15:14:43 +02001501 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1502 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001503 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001504
1505 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506}
1507
Shahar Leviae47c452011-03-06 16:32:14 +02001508int wl1271_tx_dummy_packet(struct wl1271 *wl)
1509{
Ido Yariv990f5de2011-03-31 10:06:59 +02001510 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001511 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001512
Ido Yariv990f5de2011-03-31 10:06:59 +02001513 spin_lock_irqsave(&wl->wl_lock, flags);
1514 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001515 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001516 spin_unlock_irqrestore(&wl->wl_lock, flags);
1517
1518 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1519 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1520 wl1271_tx_work_locked(wl);
1521
1522 /*
1523 * If the FW TX is busy, TX work will be scheduled by the threaded
1524 * interrupt handler function
1525 */
1526 return 0;
1527}
1528
1529/*
1530 * The size of the dummy packet should be at least 1400 bytes. However, in
1531 * order to minimize the number of bus transactions, aligning it to 512 bytes
1532 * boundaries could be beneficial, performance wise
1533 */
1534#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1535
Luciano Coelhocf27d862011-04-01 21:08:23 +03001536static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001537{
1538 struct sk_buff *skb;
1539 struct ieee80211_hdr_3addr *hdr;
1540 unsigned int dummy_packet_size;
1541
1542 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1543 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1544
1545 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001546 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001547 wl1271_warning("Failed to allocate a dummy packet skb");
1548 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001549 }
1550
1551 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1552
1553 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1554 memset(hdr, 0, sizeof(*hdr));
1555 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001556 IEEE80211_STYPE_NULLFUNC |
1557 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001558
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001560
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001561 /* Dummy packets require the TID to be management */
1562 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001563
1564 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001565 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001566 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001567
Ido Yariv990f5de2011-03-31 10:06:59 +02001568 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001569}
1570
Ido Yariv990f5de2011-03-31 10:06:59 +02001571
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001572static struct notifier_block wl1271_dev_notifier = {
1573 .notifier_call = wl1271_dev_notify,
1574};
1575
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001576#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001577static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001578{
Eliad Pellere85d1622011-06-27 13:06:43 +03001579 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001580
Eliad Peller94390642011-05-13 11:57:13 +03001581 mutex_lock(&wl->mutex);
1582
Eliad Pellere85d1622011-06-27 13:06:43 +03001583 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1584 goto out_unlock;
1585
Eliad Peller94390642011-05-13 11:57:13 +03001586 ret = wl1271_ps_elp_wakeup(wl);
1587 if (ret < 0)
1588 goto out_unlock;
1589
1590 /* enter psm if needed*/
1591 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1592 DECLARE_COMPLETION_ONSTACK(compl);
1593
1594 wl->ps_compl = &compl;
1595 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1596 wl->basic_rate, true);
1597 if (ret < 0)
1598 goto out_sleep;
1599
1600 /* we must unlock here so we will be able to get events */
1601 wl1271_ps_elp_sleep(wl);
1602 mutex_unlock(&wl->mutex);
1603
1604 ret = wait_for_completion_timeout(
1605 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1606 if (ret <= 0) {
1607 wl1271_warning("couldn't enter ps mode!");
1608 ret = -EBUSY;
1609 goto out;
1610 }
1611
1612 /* take mutex again, and wakeup */
1613 mutex_lock(&wl->mutex);
1614
1615 ret = wl1271_ps_elp_wakeup(wl);
1616 if (ret < 0)
1617 goto out_unlock;
1618 }
1619out_sleep:
1620 wl1271_ps_elp_sleep(wl);
1621out_unlock:
1622 mutex_unlock(&wl->mutex);
1623out:
1624 return ret;
1625
1626}
1627
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001628static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001629{
Eliad Pellere85d1622011-06-27 13:06:43 +03001630 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001631
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001632 mutex_lock(&wl->mutex);
1633
Eliad Pellere85d1622011-06-27 13:06:43 +03001634 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1635 goto out_unlock;
1636
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001637 ret = wl1271_ps_elp_wakeup(wl);
1638 if (ret < 0)
1639 goto out_unlock;
1640
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001641 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001642
1643 wl1271_ps_elp_sleep(wl);
1644out_unlock:
1645 mutex_unlock(&wl->mutex);
1646 return ret;
1647
1648}
1649
1650static int wl1271_configure_suspend(struct wl1271 *wl)
1651{
1652 if (wl->bss_type == BSS_TYPE_STA_BSS)
1653 return wl1271_configure_suspend_sta(wl);
1654 if (wl->bss_type == BSS_TYPE_AP_BSS)
1655 return wl1271_configure_suspend_ap(wl);
1656 return 0;
1657}
1658
1659static void wl1271_configure_resume(struct wl1271 *wl)
1660{
1661 int ret;
1662 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1663 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1664
1665 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001666 return;
1667
1668 mutex_lock(&wl->mutex);
1669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
1671 goto out;
1672
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 if (is_sta) {
1674 /* exit psm if it wasn't configured */
1675 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1676 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1677 wl->basic_rate, true);
1678 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001679 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680 }
Eliad Peller94390642011-05-13 11:57:13 +03001681
1682 wl1271_ps_elp_sleep(wl);
1683out:
1684 mutex_unlock(&wl->mutex);
1685}
1686
Eliad Peller402e48612011-05-13 11:57:09 +03001687static int wl1271_op_suspend(struct ieee80211_hw *hw,
1688 struct cfg80211_wowlan *wow)
1689{
1690 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001691 int ret;
1692
Eliad Peller402e48612011-05-13 11:57:09 +03001693 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001694 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001695
Eliad Peller4a859df2011-06-06 12:21:52 +03001696 wl->wow_enabled = true;
1697 ret = wl1271_configure_suspend(wl);
1698 if (ret < 0) {
1699 wl1271_warning("couldn't prepare device to suspend");
1700 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001701 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001702 /* flush any remaining work */
1703 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001704
1705 /*
1706 * disable and re-enable interrupts in order to flush
1707 * the threaded_irq
1708 */
1709 wl1271_disable_interrupts(wl);
1710
1711 /*
1712 * set suspended flag to avoid triggering a new threaded_irq
1713 * work. no need for spinlock as interrupts are disabled.
1714 */
1715 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1716
1717 wl1271_enable_interrupts(wl);
1718 flush_work(&wl->tx_work);
1719 flush_delayed_work(&wl->pspoll_work);
1720 flush_delayed_work(&wl->elp_work);
1721
Eliad Peller402e48612011-05-13 11:57:09 +03001722 return 0;
1723}
1724
1725static int wl1271_op_resume(struct ieee80211_hw *hw)
1726{
1727 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 unsigned long flags;
1729 bool run_irq_work = false;
1730
Eliad Peller402e48612011-05-13 11:57:09 +03001731 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1732 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001733 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001734
1735 /*
1736 * re-enable irq_work enqueuing, and call irq_work directly if
1737 * there is a pending work.
1738 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 spin_lock_irqsave(&wl->wl_lock, flags);
1740 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1741 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1742 run_irq_work = true;
1743 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001744
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 if (run_irq_work) {
1746 wl1271_debug(DEBUG_MAC80211,
1747 "run postponed irq_work directly");
1748 wl1271_irq(0, wl);
1749 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001752 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001753
Eliad Peller402e48612011-05-13 11:57:09 +03001754 return 0;
1755}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001756#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001757
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001758static int wl1271_op_start(struct ieee80211_hw *hw)
1759{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001760 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1761
1762 /*
1763 * We have to delay the booting of the hardware because
1764 * we need to know the local MAC address before downloading and
1765 * initializing the firmware. The MAC address cannot be changed
1766 * after boot, and without the proper MAC address, the firmware
1767 * will not function properly.
1768 *
1769 * The MAC address is first known when the corresponding interface
1770 * is added. That is where we will initialize the hardware.
1771 */
1772
1773 return 0;
1774}
1775
1776static void wl1271_op_stop(struct ieee80211_hw *hw)
1777{
1778 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1779}
1780
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001781static u8 wl12xx_get_role_type(struct wl1271 *wl)
1782{
1783 switch (wl->bss_type) {
1784 case BSS_TYPE_AP_BSS:
1785 return WL1271_ROLE_AP;
1786
1787 case BSS_TYPE_STA_BSS:
1788 return WL1271_ROLE_STA;
1789
Eliad Peller227e81e2011-08-14 13:17:26 +03001790 case BSS_TYPE_IBSS:
1791 return WL1271_ROLE_IBSS;
1792
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001793 default:
1794 wl1271_error("invalid bss_type: %d", wl->bss_type);
1795 }
1796 return WL12XX_INVALID_ROLE_TYPE;
1797}
1798
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001799static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1800 struct ieee80211_vif *vif)
1801{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001803 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001804 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001806 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001807 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001809 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1810 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811
1812 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001813 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001814 wl1271_debug(DEBUG_MAC80211,
1815 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001816 ret = -EBUSY;
1817 goto out;
1818 }
1819
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001820 /*
1821 * in some very corner case HW recovery scenarios its possible to
1822 * get here before __wl1271_op_remove_interface is complete, so
1823 * opt out if that is the case.
1824 */
1825 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1826 ret = -EBUSY;
1827 goto out;
1828 }
1829
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001830 switch (vif->type) {
1831 case NL80211_IFTYPE_STATION:
1832 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001833 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001834 break;
1835 case NL80211_IFTYPE_ADHOC:
1836 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001837 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001838 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001839 case NL80211_IFTYPE_AP:
1840 wl->bss_type = BSS_TYPE_AP_BSS;
1841 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001842 default:
1843 ret = -EOPNOTSUPP;
1844 goto out;
1845 }
1846
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001847 role_type = wl12xx_get_role_type(wl);
1848 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1849 ret = -EINVAL;
1850 goto out;
1851 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001852 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853
1854 if (wl->state != WL1271_STATE_OFF) {
1855 wl1271_error("cannot start because not in off state: %d",
1856 wl->state);
1857 ret = -EBUSY;
1858 goto out;
1859 }
1860
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001861 while (retries) {
1862 retries--;
1863 ret = wl1271_chip_wakeup(wl);
1864 if (ret < 0)
1865 goto power_off;
1866
1867 ret = wl1271_boot(wl);
1868 if (ret < 0)
1869 goto power_off;
1870
Eliad Peller227e81e2011-08-14 13:17:26 +03001871 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1872 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001873 /*
1874 * The device role is a special role used for
1875 * rx and tx frames prior to association (as
1876 * the STA role can get packets only from
1877 * its associated bssid)
1878 */
1879 ret = wl12xx_cmd_role_enable(wl,
1880 WL1271_ROLE_DEVICE,
1881 &wl->dev_role_id);
1882 if (ret < 0)
1883 goto irq_disable;
1884 }
1885
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1887 if (ret < 0)
1888 goto irq_disable;
1889
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001890 ret = wl1271_hw_init(wl);
1891 if (ret < 0)
1892 goto irq_disable;
1893
Eliad Peller71125ab2010-10-28 21:46:43 +02001894 booted = true;
1895 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001897irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001898 mutex_unlock(&wl->mutex);
1899 /* Unlocking the mutex in the middle of handling is
1900 inherently unsafe. In this case we deem it safe to do,
1901 because we need to let any possibly pending IRQ out of
1902 the system (and while we are WL1271_STATE_OFF the IRQ
1903 work function will not do anything.) Also, any other
1904 possible concurrent operations will fail due to the
1905 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001906 wl1271_disable_interrupts(wl);
1907 wl1271_flush_deferred_work(wl);
1908 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001909 mutex_lock(&wl->mutex);
1910power_off:
1911 wl1271_power_off(wl);
1912 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913
Eliad Peller71125ab2010-10-28 21:46:43 +02001914 if (!booted) {
1915 wl1271_error("firmware boot failed despite %d retries",
1916 WL1271_BOOT_RETRIES);
1917 goto out;
1918 }
1919
1920 wl->vif = vif;
1921 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001922 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001923 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001924
1925 /* update hw/fw version info in wiphy struct */
1926 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001927 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001928 sizeof(wiphy->fw_version));
1929
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001930 /*
1931 * Now we know if 11a is supported (info from the NVS), so disable
1932 * 11a channels if not supported
1933 */
1934 if (!wl->enable_11a)
1935 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1936
1937 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1938 wl->enable_11a ? "" : "not ");
1939
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001940out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 mutex_unlock(&wl->mutex);
1942
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001943 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001944 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001945 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001946 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 return ret;
1949}
1950
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001951static void __wl1271_op_remove_interface(struct wl1271 *wl,
1952 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001954 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001956 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001958 /* because of hardware recovery, we may get here twice */
1959 if (wl->state != WL1271_STATE_ON)
1960 return;
1961
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001962 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001964 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001965 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001966 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001967
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001968 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001969 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001970 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001971
Luciano Coelho08688d62010-07-08 17:50:07 +03001972 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001973 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001974 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001975 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001976 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 }
1978
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001979 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1980 /* disable active roles */
1981 ret = wl1271_ps_elp_wakeup(wl);
1982 if (ret < 0)
1983 goto deinit;
1984
Eliad Peller04e80792011-08-14 13:17:09 +03001985 if (wl->bss_type == BSS_TYPE_STA_BSS) {
1986 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
1987 if (ret < 0)
1988 goto deinit;
1989 }
1990
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001991 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
1992 if (ret < 0)
1993 goto deinit;
1994
1995 wl1271_ps_elp_sleep(wl);
1996 }
1997deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03001998 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001999 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002000 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002001 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2002 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002003
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002004 /*
2005 * this must be before the cancel_work calls below, so that the work
2006 * functions don't perform further work.
2007 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 wl->state = WL1271_STATE_OFF;
2009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 mutex_unlock(&wl->mutex);
2011
Ido Yariva6208652011-03-01 15:14:41 +02002012 wl1271_disable_interrupts(wl);
2013 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002014 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002015 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002017 del_timer_sync(&wl->rx_streaming_timer);
2018 cancel_work_sync(&wl->rx_streaming_enable_work);
2019 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002020 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002021 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022
2023 mutex_lock(&wl->mutex);
2024
2025 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002026 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027 wl1271_power_off(wl);
2028
2029 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002030 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002033 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002034 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035
2036 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002037 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2039 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002040 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 wl->tx_results_count = 0;
2042 wl->tx_packets_count = 0;
2043 wl->time_offset = 0;
2044 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002045 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002046 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002047 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002048 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002049 wl->ap_fw_ps_map = 0;
2050 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002051 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002052 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002053 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002054 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2055 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002056 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002057
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002058 /* The system link is always allocated */
2059 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2060
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002061 /*
2062 * this is performed after the cancel_work calls and the associated
2063 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2064 * get executed before all these vars have been reset.
2065 */
2066 wl->flags = 0;
2067
Eliad Peller4d56ad92011-08-14 13:17:05 +03002068 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069
Arik Nemtsov742246f2011-08-14 13:17:33 +03002070 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002071 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002072 wl->tx_allocated_pkts[i] = 0;
2073 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002074
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002076
2077 kfree(wl->fw_status);
2078 wl->fw_status = NULL;
2079 kfree(wl->tx_res_if);
2080 wl->tx_res_if = NULL;
2081 kfree(wl->target_mem_map);
2082 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002083}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002084
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002085static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2086 struct ieee80211_vif *vif)
2087{
2088 struct wl1271 *wl = hw->priv;
2089
2090 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002091 /*
2092 * wl->vif can be null here if someone shuts down the interface
2093 * just when hardware recovery has been started.
2094 */
2095 if (wl->vif) {
2096 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002097 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002098 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002099
Juuso Oikarinen67353292010-11-18 15:19:02 +02002100 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002101 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102}
2103
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002104static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002105{
2106 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002107 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002108
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002109 /*
2110 * One of the side effects of the JOIN command is that is clears
2111 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2112 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002113 * Currently the only valid scenario for JOIN during association
2114 * is on roaming, in which case we will also be given new keys.
2115 * Keep the below message for now, unless it starts bothering
2116 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002117 */
2118 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2119 wl1271_info("JOIN while associated.");
2120
2121 if (set_assoc)
2122 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2123
Eliad Peller227e81e2011-08-14 13:17:26 +03002124 if (is_ibss)
2125 ret = wl12xx_cmd_role_start_ibss(wl);
2126 else
2127 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002128 if (ret < 0)
2129 goto out;
2130
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002131 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2132 goto out;
2133
2134 /*
2135 * The join command disable the keep-alive mode, shut down its process,
2136 * and also clear the template config, so we need to reset it all after
2137 * the join. The acx_aid starts the keep-alive process, and the order
2138 * of the commands below is relevant.
2139 */
2140 ret = wl1271_acx_keep_alive_mode(wl, true);
2141 if (ret < 0)
2142 goto out;
2143
2144 ret = wl1271_acx_aid(wl, wl->aid);
2145 if (ret < 0)
2146 goto out;
2147
2148 ret = wl1271_cmd_build_klv_null_data(wl);
2149 if (ret < 0)
2150 goto out;
2151
2152 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2153 ACX_KEEP_ALIVE_TPL_VALID);
2154 if (ret < 0)
2155 goto out;
2156
2157out:
2158 return ret;
2159}
2160
2161static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002162{
2163 int ret;
2164
2165 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002166 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002167 if (ret < 0)
2168 goto out;
2169
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002170 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002171
Oz Krakowskib992c682011-06-26 10:36:02 +03002172 /* reset TX security counters on a clean disconnect */
2173 wl->tx_security_last_seq_lsb = 0;
2174 wl->tx_security_seq = 0;
2175
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002176out:
2177 return ret;
2178}
2179
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002180static void wl1271_set_band_rate(struct wl1271 *wl)
2181{
2182 if (wl->band == IEEE80211_BAND_2GHZ)
2183 wl->basic_rate_set = wl->conf.tx.basic_rate;
2184 else
2185 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2186}
2187
Eliad Peller251c1772011-08-14 13:17:17 +03002188static bool wl12xx_is_roc(struct wl1271 *wl)
2189{
2190 u8 role_id;
2191
2192 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2193 if (role_id >= WL12XX_MAX_ROLES)
2194 return false;
2195
2196 return true;
2197}
2198
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002199static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002200{
2201 int ret;
2202
2203 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002204 /* no need to croc if we weren't busy (e.g. during boot) */
2205 if (wl12xx_is_roc(wl)) {
2206 ret = wl12xx_croc(wl, wl->dev_role_id);
2207 if (ret < 0)
2208 goto out;
2209
2210 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002211 if (ret < 0)
2212 goto out;
2213 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002214 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002215 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002216 if (ret < 0)
2217 goto out;
2218 ret = wl1271_acx_keep_alive_config(
2219 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2220 ACX_KEEP_ALIVE_TPL_INVALID);
2221 if (ret < 0)
2222 goto out;
2223 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2224 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002225 /* The current firmware only supports sched_scan in idle */
2226 if (wl->sched_scanning) {
2227 wl1271_scan_sched_scan_stop(wl);
2228 ieee80211_sched_scan_stopped(wl->hw);
2229 }
2230
Eliad Peller251c1772011-08-14 13:17:17 +03002231 ret = wl12xx_cmd_role_start_dev(wl);
2232 if (ret < 0)
2233 goto out;
2234
2235 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002236 if (ret < 0)
2237 goto out;
2238 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2239 }
2240
2241out:
2242 return ret;
2243}
2244
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002245static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2246{
2247 struct wl1271 *wl = hw->priv;
2248 struct ieee80211_conf *conf = &hw->conf;
2249 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002250 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251
2252 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2253
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002254 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2255 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002256 channel,
2257 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002258 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002259 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2260 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002262 /*
2263 * mac80211 will go to idle nearly immediately after transmitting some
2264 * frames, such as the deauth. To make sure those frames reach the air,
2265 * wait here until the TX queue is fully flushed.
2266 */
2267 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2268 (conf->flags & IEEE80211_CONF_IDLE))
2269 wl1271_tx_flush(wl);
2270
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271 mutex_lock(&wl->mutex);
2272
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002273 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002274 /* we support configuring the channel and band while off */
2275 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2276 wl->band = conf->channel->band;
2277 wl->channel = channel;
2278 }
2279
Arik Nemtsov097f8822011-06-27 22:06:34 +03002280 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2281 wl->power_level = conf->power_level;
2282
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002283 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002284 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002285
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002286 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2287
Ido Yariva6208652011-03-01 15:14:41 +02002288 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289 if (ret < 0)
2290 goto out;
2291
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002292 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002293 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2294 ((wl->band != conf->channel->band) ||
2295 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002296 wl->band = conf->channel->band;
2297 wl->channel = channel;
2298
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002299 if (!is_ap) {
2300 /*
2301 * FIXME: the mac80211 should really provide a fixed
2302 * rate to use here. for now, just use the smallest
2303 * possible rate for the band as a fixed rate for
2304 * association frames and other control messages.
2305 */
2306 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2307 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002308
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002309 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2310 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002311 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002312 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002313 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002314
Eliad Peller251c1772011-08-14 13:17:17 +03002315 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2316 if (wl12xx_is_roc(wl)) {
2317 /* roaming */
2318 ret = wl12xx_croc(wl, wl->dev_role_id);
2319 if (ret < 0)
2320 goto out_sleep;
2321 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002322 ret = wl1271_join(wl, false);
2323 if (ret < 0)
2324 wl1271_warning("cmd join on channel "
2325 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002326 } else {
2327 /*
2328 * change the ROC channel. do it only if we are
2329 * not idle. otherwise, CROC will be called
2330 * anyway.
2331 */
2332 if (wl12xx_is_roc(wl) &&
2333 !(conf->flags & IEEE80211_CONF_IDLE)) {
2334 ret = wl12xx_croc(wl, wl->dev_role_id);
2335 if (ret < 0)
2336 goto out_sleep;
2337
2338 ret = wl12xx_roc(wl, wl->dev_role_id);
2339 if (ret < 0)
2340 wl1271_warning("roc failed %d",
2341 ret);
2342 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002343 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002344 }
2345 }
2346
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002347 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2348 ret = wl1271_sta_handle_idle(wl,
2349 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002350 if (ret < 0)
2351 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 }
2353
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002354 /*
2355 * if mac80211 changes the PSM mode, make sure the mode is not
2356 * incorrectly changed after the pspoll failure active window.
2357 */
2358 if (changed & IEEE80211_CONF_CHANGE_PS)
2359 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2360
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002361 if (conf->flags & IEEE80211_CONF_PS &&
2362 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2363 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364
2365 /*
2366 * We enter PSM only if we're already associated.
2367 * If we're not, we'll enter it when joining an SSID,
2368 * through the bss_info_changed() hook.
2369 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002370 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002371 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002372 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002373 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002374 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002376 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002377 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002379 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002381 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002382 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002383 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384 }
2385
2386 if (conf->power_level != wl->power_level) {
2387 ret = wl1271_acx_tx_power(wl, conf->power_level);
2388 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002389 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390
2391 wl->power_level = conf->power_level;
2392 }
2393
2394out_sleep:
2395 wl1271_ps_elp_sleep(wl);
2396
2397out:
2398 mutex_unlock(&wl->mutex);
2399
2400 return ret;
2401}
2402
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002403struct wl1271_filter_params {
2404 bool enabled;
2405 int mc_list_length;
2406 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2407};
2408
Jiri Pirko22bedad32010-04-01 21:22:57 +00002409static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2410 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002411{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002412 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002413 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002414 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002415
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002416 if (unlikely(wl->state == WL1271_STATE_OFF))
2417 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002418
Juuso Oikarinen74441132009-10-13 12:47:53 +03002419 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002420 if (!fp) {
2421 wl1271_error("Out of memory setting filters.");
2422 return 0;
2423 }
2424
2425 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002426 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002427 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2428 fp->enabled = false;
2429 } else {
2430 fp->enabled = true;
2431 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002432 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002433 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002434 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002435 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002436 }
2437
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002438 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002439}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002441#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2442 FIF_ALLMULTI | \
2443 FIF_FCSFAIL | \
2444 FIF_BCN_PRBRESP_PROMISC | \
2445 FIF_CONTROL | \
2446 FIF_OTHER_BSS)
2447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2449 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002450 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002451{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002452 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002454 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455
Arik Nemtsov7d057862010-10-16 19:25:35 +02002456 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2457 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002459 mutex_lock(&wl->mutex);
2460
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002461 *total &= WL1271_SUPPORTED_FILTERS;
2462 changed &= WL1271_SUPPORTED_FILTERS;
2463
2464 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002465 goto out;
2466
Ido Yariva6208652011-03-01 15:14:41 +02002467 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002468 if (ret < 0)
2469 goto out;
2470
Arik Nemtsov7d057862010-10-16 19:25:35 +02002471 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2472 if (*total & FIF_ALLMULTI)
2473 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2474 else if (fp)
2475 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2476 fp->mc_list,
2477 fp->mc_list_length);
2478 if (ret < 0)
2479 goto out_sleep;
2480 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002482 /*
2483 * the fw doesn't provide an api to configure the filters. instead,
2484 * the filters configuration is based on the active roles / ROC
2485 * state.
2486 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002487
2488out_sleep:
2489 wl1271_ps_elp_sleep(wl);
2490
2491out:
2492 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002493 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002494}
2495
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002496static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2497 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2498 u16 tx_seq_16)
2499{
2500 struct wl1271_ap_key *ap_key;
2501 int i;
2502
2503 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2504
2505 if (key_size > MAX_KEY_SIZE)
2506 return -EINVAL;
2507
2508 /*
2509 * Find next free entry in ap_keys. Also check we are not replacing
2510 * an existing key.
2511 */
2512 for (i = 0; i < MAX_NUM_KEYS; i++) {
2513 if (wl->recorded_ap_keys[i] == NULL)
2514 break;
2515
2516 if (wl->recorded_ap_keys[i]->id == id) {
2517 wl1271_warning("trying to record key replacement");
2518 return -EINVAL;
2519 }
2520 }
2521
2522 if (i == MAX_NUM_KEYS)
2523 return -EBUSY;
2524
2525 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2526 if (!ap_key)
2527 return -ENOMEM;
2528
2529 ap_key->id = id;
2530 ap_key->key_type = key_type;
2531 ap_key->key_size = key_size;
2532 memcpy(ap_key->key, key, key_size);
2533 ap_key->hlid = hlid;
2534 ap_key->tx_seq_32 = tx_seq_32;
2535 ap_key->tx_seq_16 = tx_seq_16;
2536
2537 wl->recorded_ap_keys[i] = ap_key;
2538 return 0;
2539}
2540
2541static void wl1271_free_ap_keys(struct wl1271 *wl)
2542{
2543 int i;
2544
2545 for (i = 0; i < MAX_NUM_KEYS; i++) {
2546 kfree(wl->recorded_ap_keys[i]);
2547 wl->recorded_ap_keys[i] = NULL;
2548 }
2549}
2550
2551static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2552{
2553 int i, ret = 0;
2554 struct wl1271_ap_key *key;
2555 bool wep_key_added = false;
2556
2557 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002558 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002559 if (wl->recorded_ap_keys[i] == NULL)
2560 break;
2561
2562 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002563 hlid = key->hlid;
2564 if (hlid == WL12XX_INVALID_LINK_ID)
2565 hlid = wl->ap_bcast_hlid;
2566
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002567 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2568 key->id, key->key_type,
2569 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002570 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002571 key->tx_seq_16);
2572 if (ret < 0)
2573 goto out;
2574
2575 if (key->key_type == KEY_WEP)
2576 wep_key_added = true;
2577 }
2578
2579 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002580 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002581 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002582 if (ret < 0)
2583 goto out;
2584 }
2585
2586out:
2587 wl1271_free_ap_keys(wl);
2588 return ret;
2589}
2590
2591static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2592 u8 key_size, const u8 *key, u32 tx_seq_32,
2593 u16 tx_seq_16, struct ieee80211_sta *sta)
2594{
2595 int ret;
2596 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2597
2598 if (is_ap) {
2599 struct wl1271_station *wl_sta;
2600 u8 hlid;
2601
2602 if (sta) {
2603 wl_sta = (struct wl1271_station *)sta->drv_priv;
2604 hlid = wl_sta->hlid;
2605 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002606 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002607 }
2608
2609 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2610 /*
2611 * We do not support removing keys after AP shutdown.
2612 * Pretend we do to make mac80211 happy.
2613 */
2614 if (action != KEY_ADD_OR_REPLACE)
2615 return 0;
2616
2617 ret = wl1271_record_ap_key(wl, id,
2618 key_type, key_size,
2619 key, hlid, tx_seq_32,
2620 tx_seq_16);
2621 } else {
2622 ret = wl1271_cmd_set_ap_key(wl, action,
2623 id, key_type, key_size,
2624 key, hlid, tx_seq_32,
2625 tx_seq_16);
2626 }
2627
2628 if (ret < 0)
2629 return ret;
2630 } else {
2631 const u8 *addr;
2632 static const u8 bcast_addr[ETH_ALEN] = {
2633 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2634 };
2635
2636 addr = sta ? sta->addr : bcast_addr;
2637
2638 if (is_zero_ether_addr(addr)) {
2639 /* We dont support TX only encryption */
2640 return -EOPNOTSUPP;
2641 }
2642
2643 /* The wl1271 does not allow to remove unicast keys - they
2644 will be cleared automatically on next CMD_JOIN. Ignore the
2645 request silently, as we dont want the mac80211 to emit
2646 an error message. */
2647 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2648 return 0;
2649
Eliad Peller010d3d32011-08-14 13:17:31 +03002650 /* don't remove key if hlid was already deleted */
2651 if (action == KEY_REMOVE &&
2652 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2653 return 0;
2654
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002655 ret = wl1271_cmd_set_sta_key(wl, action,
2656 id, key_type, key_size,
2657 key, addr, tx_seq_32,
2658 tx_seq_16);
2659 if (ret < 0)
2660 return ret;
2661
2662 /* the default WEP key needs to be configured at least once */
2663 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002664 ret = wl12xx_cmd_set_default_wep_key(wl,
2665 wl->default_key,
2666 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002667 if (ret < 0)
2668 return ret;
2669 }
2670 }
2671
2672 return 0;
2673}
2674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2676 struct ieee80211_vif *vif,
2677 struct ieee80211_sta *sta,
2678 struct ieee80211_key_conf *key_conf)
2679{
2680 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002682 u32 tx_seq_32 = 0;
2683 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684 u8 key_type;
2685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2687
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002688 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002690 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002691 key_conf->keylen, key_conf->flags);
2692 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 mutex_lock(&wl->mutex);
2695
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002696 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2697 ret = -EAGAIN;
2698 goto out_unlock;
2699 }
2700
Ido Yariva6208652011-03-01 15:14:41 +02002701 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702 if (ret < 0)
2703 goto out_unlock;
2704
Johannes Berg97359d12010-08-10 09:46:38 +02002705 switch (key_conf->cipher) {
2706 case WLAN_CIPHER_SUITE_WEP40:
2707 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708 key_type = KEY_WEP;
2709
2710 key_conf->hw_key_idx = key_conf->keyidx;
2711 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002712 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 key_type = KEY_TKIP;
2714
2715 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002716 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2717 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002718 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002719 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720 key_type = KEY_AES;
2721
2722 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002723 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2724 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002726 case WL1271_CIPHER_SUITE_GEM:
2727 key_type = KEY_GEM;
2728 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2729 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2730 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002732 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733
2734 ret = -EOPNOTSUPP;
2735 goto out_sleep;
2736 }
2737
2738 switch (cmd) {
2739 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002740 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2741 key_conf->keyidx, key_type,
2742 key_conf->keylen, key_conf->key,
2743 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002744 if (ret < 0) {
2745 wl1271_error("Could not add or replace key");
2746 goto out_sleep;
2747 }
2748 break;
2749
2750 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002751 ret = wl1271_set_key(wl, KEY_REMOVE,
2752 key_conf->keyidx, key_type,
2753 key_conf->keylen, key_conf->key,
2754 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002755 if (ret < 0) {
2756 wl1271_error("Could not remove key");
2757 goto out_sleep;
2758 }
2759 break;
2760
2761 default:
2762 wl1271_error("Unsupported key cmd 0x%x", cmd);
2763 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002764 break;
2765 }
2766
2767out_sleep:
2768 wl1271_ps_elp_sleep(wl);
2769
2770out_unlock:
2771 mutex_unlock(&wl->mutex);
2772
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002773 return ret;
2774}
2775
2776static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002777 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002778 struct cfg80211_scan_request *req)
2779{
2780 struct wl1271 *wl = hw->priv;
2781 int ret;
2782 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002783 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002784
2785 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2786
2787 if (req->n_ssids) {
2788 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002789 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 }
2791
2792 mutex_lock(&wl->mutex);
2793
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002794 if (wl->state == WL1271_STATE_OFF) {
2795 /*
2796 * We cannot return -EBUSY here because cfg80211 will expect
2797 * a call to ieee80211_scan_completed if we do - in this case
2798 * there won't be any call.
2799 */
2800 ret = -EAGAIN;
2801 goto out;
2802 }
2803
Ido Yariva6208652011-03-01 15:14:41 +02002804 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002805 if (ret < 0)
2806 goto out;
2807
Eliad Peller251c1772011-08-14 13:17:17 +03002808 /* cancel ROC before scanning */
2809 if (wl12xx_is_roc(wl)) {
2810 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2811 /* don't allow scanning right now */
2812 ret = -EBUSY;
2813 goto out_sleep;
2814 }
2815 wl12xx_croc(wl, wl->dev_role_id);
2816 wl12xx_cmd_role_stop_dev(wl);
2817 }
2818
Luciano Coelho5924f892010-08-04 03:46:22 +03002819 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002820out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002822out:
2823 mutex_unlock(&wl->mutex);
2824
2825 return ret;
2826}
2827
Eliad Peller73ecce32011-06-27 13:06:45 +03002828static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2829 struct ieee80211_vif *vif)
2830{
2831 struct wl1271 *wl = hw->priv;
2832 int ret;
2833
2834 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2835
2836 mutex_lock(&wl->mutex);
2837
2838 if (wl->state == WL1271_STATE_OFF)
2839 goto out;
2840
2841 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2842 goto out;
2843
2844 ret = wl1271_ps_elp_wakeup(wl);
2845 if (ret < 0)
2846 goto out;
2847
2848 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2849 ret = wl1271_scan_stop(wl);
2850 if (ret < 0)
2851 goto out_sleep;
2852 }
2853 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2854 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2855 wl->scan.req = NULL;
2856 ieee80211_scan_completed(wl->hw, true);
2857
2858out_sleep:
2859 wl1271_ps_elp_sleep(wl);
2860out:
2861 mutex_unlock(&wl->mutex);
2862
2863 cancel_delayed_work_sync(&wl->scan_complete_work);
2864}
2865
Luciano Coelho33c2c062011-05-10 14:46:02 +03002866static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2867 struct ieee80211_vif *vif,
2868 struct cfg80211_sched_scan_request *req,
2869 struct ieee80211_sched_scan_ies *ies)
2870{
2871 struct wl1271 *wl = hw->priv;
2872 int ret;
2873
2874 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2875
2876 mutex_lock(&wl->mutex);
2877
2878 ret = wl1271_ps_elp_wakeup(wl);
2879 if (ret < 0)
2880 goto out;
2881
2882 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2883 if (ret < 0)
2884 goto out_sleep;
2885
2886 ret = wl1271_scan_sched_scan_start(wl);
2887 if (ret < 0)
2888 goto out_sleep;
2889
2890 wl->sched_scanning = true;
2891
2892out_sleep:
2893 wl1271_ps_elp_sleep(wl);
2894out:
2895 mutex_unlock(&wl->mutex);
2896 return ret;
2897}
2898
2899static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2900 struct ieee80211_vif *vif)
2901{
2902 struct wl1271 *wl = hw->priv;
2903 int ret;
2904
2905 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2906
2907 mutex_lock(&wl->mutex);
2908
2909 ret = wl1271_ps_elp_wakeup(wl);
2910 if (ret < 0)
2911 goto out;
2912
2913 wl1271_scan_sched_scan_stop(wl);
2914
2915 wl1271_ps_elp_sleep(wl);
2916out:
2917 mutex_unlock(&wl->mutex);
2918}
2919
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002920static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2921{
2922 struct wl1271 *wl = hw->priv;
2923 int ret = 0;
2924
2925 mutex_lock(&wl->mutex);
2926
2927 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2928 ret = -EAGAIN;
2929 goto out;
2930 }
2931
Ido Yariva6208652011-03-01 15:14:41 +02002932 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002933 if (ret < 0)
2934 goto out;
2935
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002936 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002937 if (ret < 0)
2938 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2939
2940 wl1271_ps_elp_sleep(wl);
2941
2942out:
2943 mutex_unlock(&wl->mutex);
2944
2945 return ret;
2946}
2947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2949{
2950 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002951 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952
2953 mutex_lock(&wl->mutex);
2954
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002955 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2956 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002957 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002958 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002959
Ido Yariva6208652011-03-01 15:14:41 +02002960 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 if (ret < 0)
2962 goto out;
2963
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002964 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965 if (ret < 0)
2966 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2967
2968 wl1271_ps_elp_sleep(wl);
2969
2970out:
2971 mutex_unlock(&wl->mutex);
2972
2973 return ret;
2974}
2975
Arik Nemtsove78a2872010-10-16 19:07:21 +02002976static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002977 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002978{
Eliad Peller889cb362011-05-01 09:56:45 +03002979 u8 ssid_len;
2980 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2981 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002982
Eliad Peller889cb362011-05-01 09:56:45 +03002983 if (!ptr) {
2984 wl1271_error("No SSID in IEs!");
2985 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002986 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002987
Eliad Peller889cb362011-05-01 09:56:45 +03002988 ssid_len = ptr[1];
2989 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2990 wl1271_error("SSID is too long!");
2991 return -EINVAL;
2992 }
2993
2994 wl->ssid_len = ssid_len;
2995 memcpy(wl->ssid, ptr+2, ssid_len);
2996 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002997}
2998
Arik Nemtsove78a2872010-10-16 19:07:21 +02002999static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3000 struct ieee80211_bss_conf *bss_conf,
3001 u32 changed)
3002{
3003 int ret = 0;
3004
3005 if (changed & BSS_CHANGED_ERP_SLOT) {
3006 if (bss_conf->use_short_slot)
3007 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3008 else
3009 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3010 if (ret < 0) {
3011 wl1271_warning("Set slot time failed %d", ret);
3012 goto out;
3013 }
3014 }
3015
3016 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3017 if (bss_conf->use_short_preamble)
3018 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3019 else
3020 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3021 }
3022
3023 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3024 if (bss_conf->use_cts_prot)
3025 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3026 else
3027 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3028 if (ret < 0) {
3029 wl1271_warning("Set ctsprotect failed %d", ret);
3030 goto out;
3031 }
3032 }
3033
3034out:
3035 return ret;
3036}
3037
3038static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3039 struct ieee80211_vif *vif,
3040 struct ieee80211_bss_conf *bss_conf,
3041 u32 changed)
3042{
3043 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3044 int ret = 0;
3045
3046 if ((changed & BSS_CHANGED_BEACON_INT)) {
3047 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3048 bss_conf->beacon_int);
3049
3050 wl->beacon_int = bss_conf->beacon_int;
3051 }
3052
3053 if ((changed & BSS_CHANGED_BEACON)) {
3054 struct ieee80211_hdr *hdr;
3055 int ieoffset = offsetof(struct ieee80211_mgmt,
3056 u.beacon.variable);
3057 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3058 u16 tmpl_id;
3059
3060 if (!beacon)
3061 goto out;
3062
3063 wl1271_debug(DEBUG_MASTER, "beacon updated");
3064
3065 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3066 if (ret < 0) {
3067 dev_kfree_skb(beacon);
3068 goto out;
3069 }
3070 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3071 CMD_TEMPL_BEACON;
3072 ret = wl1271_cmd_template_set(wl, tmpl_id,
3073 beacon->data,
3074 beacon->len, 0,
3075 wl1271_tx_min_rate_get(wl));
3076 if (ret < 0) {
3077 dev_kfree_skb(beacon);
3078 goto out;
3079 }
3080
3081 hdr = (struct ieee80211_hdr *) beacon->data;
3082 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3083 IEEE80211_STYPE_PROBE_RESP);
3084
3085 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3086 CMD_TEMPL_PROBE_RESPONSE;
3087 ret = wl1271_cmd_template_set(wl,
3088 tmpl_id,
3089 beacon->data,
3090 beacon->len, 0,
3091 wl1271_tx_min_rate_get(wl));
3092 dev_kfree_skb(beacon);
3093 if (ret < 0)
3094 goto out;
3095 }
3096
3097out:
3098 return ret;
3099}
3100
3101/* AP mode changes */
3102static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003103 struct ieee80211_vif *vif,
3104 struct ieee80211_bss_conf *bss_conf,
3105 u32 changed)
3106{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003107 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003108
Arik Nemtsove78a2872010-10-16 19:07:21 +02003109 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3110 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111
Arik Nemtsove78a2872010-10-16 19:07:21 +02003112 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3113 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114
Arik Nemtsov70f47422011-04-18 14:15:25 +03003115 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003116 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003117 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003118 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003119 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003120
3121 ret = wl1271_ap_init_templates(wl);
3122 if (ret < 0)
3123 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003124 }
3125
Arik Nemtsove78a2872010-10-16 19:07:21 +02003126 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3127 if (ret < 0)
3128 goto out;
3129
3130 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3131 if (bss_conf->enable_beacon) {
3132 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003133 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003134 if (ret < 0)
3135 goto out;
3136
3137 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3138 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003139
3140 ret = wl1271_ap_init_hwenc(wl);
3141 if (ret < 0)
3142 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003143 }
3144 } else {
3145 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003146 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003147 if (ret < 0)
3148 goto out;
3149
3150 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3151 wl1271_debug(DEBUG_AP, "stopped AP");
3152 }
3153 }
3154 }
3155
3156 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3157 if (ret < 0)
3158 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003159
3160 /* Handle HT information change */
3161 if ((changed & BSS_CHANGED_HT) &&
3162 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3163 ret = wl1271_acx_set_ht_information(wl,
3164 bss_conf->ht_operation_mode);
3165 if (ret < 0) {
3166 wl1271_warning("Set ht information failed %d", ret);
3167 goto out;
3168 }
3169 }
3170
Arik Nemtsove78a2872010-10-16 19:07:21 +02003171out:
3172 return;
3173}
3174
3175/* STA/IBSS mode changes */
3176static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3177 struct ieee80211_vif *vif,
3178 struct ieee80211_bss_conf *bss_conf,
3179 u32 changed)
3180{
3181 bool do_join = false, set_assoc = false;
3182 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003183 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003184 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003185 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003186 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003187 bool sta_exists = false;
3188 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003189
3190 if (is_ibss) {
3191 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3192 changed);
3193 if (ret < 0)
3194 goto out;
3195 }
3196
Eliad Peller227e81e2011-08-14 13:17:26 +03003197 if (changed & BSS_CHANGED_IBSS) {
3198 if (bss_conf->ibss_joined) {
3199 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3200 ibss_joined = true;
3201 } else {
3202 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3203 &wl->flags)) {
3204 wl1271_unjoin(wl);
3205 wl12xx_cmd_role_start_dev(wl);
3206 wl12xx_roc(wl, wl->dev_role_id);
3207 }
3208 }
3209 }
3210
3211 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003212 do_join = true;
3213
3214 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003215 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003216 do_join = true;
3217
Eliad Peller227e81e2011-08-14 13:17:26 +03003218 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003219 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3220 bss_conf->enable_beacon ? "enabled" : "disabled");
3221
3222 if (bss_conf->enable_beacon)
3223 wl->set_bss_type = BSS_TYPE_IBSS;
3224 else
3225 wl->set_bss_type = BSS_TYPE_STA_BSS;
3226 do_join = true;
3227 }
3228
Arik Nemtsove78a2872010-10-16 19:07:21 +02003229 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003230 bool enable = false;
3231 if (bss_conf->cqm_rssi_thold)
3232 enable = true;
3233 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3234 bss_conf->cqm_rssi_thold,
3235 bss_conf->cqm_rssi_hyst);
3236 if (ret < 0)
3237 goto out;
3238 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3239 }
3240
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003241 if ((changed & BSS_CHANGED_BSSID) &&
3242 /*
3243 * Now we know the correct bssid, so we send a new join command
3244 * and enable the BSSID filter
3245 */
3246 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003247 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003248
Eliad Pellerfa287b82010-12-26 09:27:50 +01003249 if (!is_zero_ether_addr(wl->bssid)) {
3250 ret = wl1271_cmd_build_null_data(wl);
3251 if (ret < 0)
3252 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003253
Eliad Pellerfa287b82010-12-26 09:27:50 +01003254 ret = wl1271_build_qos_null_data(wl);
3255 if (ret < 0)
3256 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003257
Eliad Pellerfa287b82010-12-26 09:27:50 +01003258 /* Need to update the BSSID (for filtering etc) */
3259 do_join = true;
3260 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003261 }
3262
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003263 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3264 rcu_read_lock();
3265 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3266 if (!sta)
3267 goto sta_not_found;
3268
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003269 /* save the supp_rates of the ap */
3270 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3271 if (sta->ht_cap.ht_supported)
3272 sta_rate_set |=
3273 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003274 sta_ht_cap = sta->ht_cap;
3275 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003276
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003277sta_not_found:
3278 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003279 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003280
Arik Nemtsove78a2872010-10-16 19:07:21 +02003281 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003282 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003283 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003284 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003285 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003286 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003287
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003288 wl->ps_poll_failures = 0;
3289
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003290 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003291 * use basic rates from AP, and determine lowest rate
3292 * to use with control frames.
3293 */
3294 rates = bss_conf->basic_rates;
3295 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3296 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003297 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003298 if (sta_rate_set)
3299 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3300 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003301 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003302 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003303 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003304
3305 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003306 * with wl1271, we don't need to update the
3307 * beacon_int and dtim_period, because the firmware
3308 * updates it by itself when the first beacon is
3309 * received after a join.
3310 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3312 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003314
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003315 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003316 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003317 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003318 dev_kfree_skb(wl->probereq);
3319 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3320 ieoffset = offsetof(struct ieee80211_mgmt,
3321 u.probe_req.variable);
3322 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003323
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003324 /* enable the connection monitoring feature */
3325 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003326 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328
3329 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003330 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3331 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003332 enum wl1271_cmd_ps_mode mode;
3333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003334 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003335 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003336 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003337 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003338 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003339 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003341 } else {
3342 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003343 bool was_assoc =
3344 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3345 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003346 bool was_ifup =
3347 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3348 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003349 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003350
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003351 /* free probe-request template */
3352 dev_kfree_skb(wl->probereq);
3353 wl->probereq = NULL;
3354
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003355 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003356 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003357
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003358 /* revert back to minimum rates for the current band */
3359 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003360 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003361 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003362 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003364
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003365 /* disable connection monitor features */
3366 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003367
3368 /* Disable the keep-alive feature */
3369 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003370 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003372
3373 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003374 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003375 u32 conf_flags = wl->hw->conf.flags;
3376 /*
3377 * we might have to disable roc, if there was
3378 * no IF_OPER_UP notification.
3379 */
3380 if (!was_ifup) {
3381 ret = wl12xx_croc(wl, wl->role_id);
3382 if (ret < 0)
3383 goto out;
3384 }
3385 /*
3386 * (we also need to disable roc in case of
3387 * roaming on the same channel. until we will
3388 * have a better flow...)
3389 */
3390 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3391 ret = wl12xx_croc(wl, wl->dev_role_id);
3392 if (ret < 0)
3393 goto out;
3394 }
3395
Eliad Peller30df14d2011-04-05 19:13:28 +03003396 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003397 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3398 wl12xx_cmd_role_start_dev(wl);
3399 wl12xx_roc(wl, wl->dev_role_id);
3400 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003401 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003402 }
3403 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003404
Eliad Pellerd192d262011-05-24 14:33:08 +03003405 if (changed & BSS_CHANGED_IBSS) {
3406 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3407 bss_conf->ibss_joined);
3408
3409 if (bss_conf->ibss_joined) {
3410 u32 rates = bss_conf->basic_rates;
3411 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3412 rates);
3413 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3414
3415 /* by default, use 11b rates */
3416 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3417 ret = wl1271_acx_sta_rate_policies(wl);
3418 if (ret < 0)
3419 goto out;
3420 }
3421 }
3422
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3424 if (ret < 0)
3425 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003426
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003427 if (changed & BSS_CHANGED_ARP_FILTER) {
3428 __be32 addr = bss_conf->arp_addr_list[0];
3429 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3430
Eliad Pellerc5312772010-12-09 11:31:27 +02003431 if (bss_conf->arp_addr_cnt == 1 &&
3432 bss_conf->arp_filter_enabled) {
3433 /*
3434 * The template should have been configured only upon
3435 * association. however, it seems that the correct ip
3436 * isn't being set (when sending), so we have to
3437 * reconfigure the template upon every ip change.
3438 */
3439 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3440 if (ret < 0) {
3441 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003443 }
3444
3445 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003446 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003447 addr);
3448 } else
3449 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003450
3451 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003453 }
3454
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003455 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003456 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003457 if (ret < 0) {
3458 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003459 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003460 }
Eliad Peller251c1772011-08-14 13:17:17 +03003461
3462 /* ROC until connected (after EAPOL exchange) */
3463 if (!is_ibss) {
3464 ret = wl12xx_roc(wl, wl->role_id);
3465 if (ret < 0)
3466 goto out;
3467
3468 wl1271_check_operstate(wl,
3469 ieee80211_get_operstate(vif));
3470 }
3471 /*
3472 * stop device role if started (we might already be in
3473 * STA role). TODO: make it better.
3474 */
3475 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3476 ret = wl12xx_croc(wl, wl->dev_role_id);
3477 if (ret < 0)
3478 goto out;
3479
3480 ret = wl12xx_cmd_role_stop_dev(wl);
3481 if (ret < 0)
3482 goto out;
3483 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003484 }
3485
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003486 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003487 if (sta_exists) {
3488 if ((changed & BSS_CHANGED_HT) &&
3489 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003490 ret = wl1271_acx_set_ht_capabilities(wl,
3491 &sta_ht_cap,
3492 true,
3493 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003494 if (ret < 0) {
3495 wl1271_warning("Set ht cap true failed %d",
3496 ret);
3497 goto out;
3498 }
3499 }
3500 /* handle new association without HT and disassociation */
3501 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003502 ret = wl1271_acx_set_ht_capabilities(wl,
3503 &sta_ht_cap,
3504 false,
3505 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003506 if (ret < 0) {
3507 wl1271_warning("Set ht cap false failed %d",
3508 ret);
3509 goto out;
3510 }
3511 }
3512 }
3513
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003514 /* Handle HT information change. Done after join. */
3515 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003516 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3517 ret = wl1271_acx_set_ht_information(wl,
3518 bss_conf->ht_operation_mode);
3519 if (ret < 0) {
3520 wl1271_warning("Set ht information failed %d", ret);
3521 goto out;
3522 }
3523 }
3524
Arik Nemtsove78a2872010-10-16 19:07:21 +02003525out:
3526 return;
3527}
3528
3529static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3530 struct ieee80211_vif *vif,
3531 struct ieee80211_bss_conf *bss_conf,
3532 u32 changed)
3533{
3534 struct wl1271 *wl = hw->priv;
3535 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3536 int ret;
3537
3538 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3539 (int)changed);
3540
3541 mutex_lock(&wl->mutex);
3542
3543 if (unlikely(wl->state == WL1271_STATE_OFF))
3544 goto out;
3545
Ido Yariva6208652011-03-01 15:14:41 +02003546 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 if (ret < 0)
3548 goto out;
3549
3550 if (is_ap)
3551 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3552 else
3553 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3554
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003555 wl1271_ps_elp_sleep(wl);
3556
3557out:
3558 mutex_unlock(&wl->mutex);
3559}
3560
Kalle Valoc6999d82010-02-18 13:25:41 +02003561static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3562 const struct ieee80211_tx_queue_params *params)
3563{
3564 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003565 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003566 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003567
3568 mutex_lock(&wl->mutex);
3569
3570 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3571
Kalle Valo4695dc92010-03-18 12:26:38 +02003572 if (params->uapsd)
3573 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3574 else
3575 ps_scheme = CONF_PS_SCHEME_LEGACY;
3576
Arik Nemtsov488fc542010-10-16 20:33:45 +02003577 if (wl->state == WL1271_STATE_OFF) {
3578 /*
3579 * If the state is off, the parameters will be recorded and
3580 * configured on init. This happens in AP-mode.
3581 */
3582 struct conf_tx_ac_category *conf_ac =
3583 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3584 struct conf_tx_tid *conf_tid =
3585 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3586
3587 conf_ac->ac = wl1271_tx_get_queue(queue);
3588 conf_ac->cw_min = (u8)params->cw_min;
3589 conf_ac->cw_max = params->cw_max;
3590 conf_ac->aifsn = params->aifs;
3591 conf_ac->tx_op_limit = params->txop << 5;
3592
3593 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3594 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3595 conf_tid->tsid = wl1271_tx_get_queue(queue);
3596 conf_tid->ps_scheme = ps_scheme;
3597 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3598 conf_tid->apsd_conf[0] = 0;
3599 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003600 goto out;
3601 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003602
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003603 ret = wl1271_ps_elp_wakeup(wl);
3604 if (ret < 0)
3605 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003606
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003607 /*
3608 * the txop is confed in units of 32us by the mac80211,
3609 * we need us
3610 */
3611 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3612 params->cw_min, params->cw_max,
3613 params->aifs, params->txop << 5);
3614 if (ret < 0)
3615 goto out_sleep;
3616
3617 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3618 CONF_CHANNEL_TYPE_EDCF,
3619 wl1271_tx_get_queue(queue),
3620 ps_scheme, CONF_ACK_POLICY_LEGACY,
3621 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003622
3623out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003624 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003625
3626out:
3627 mutex_unlock(&wl->mutex);
3628
3629 return ret;
3630}
3631
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003632static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3633{
3634
3635 struct wl1271 *wl = hw->priv;
3636 u64 mactime = ULLONG_MAX;
3637 int ret;
3638
3639 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3640
3641 mutex_lock(&wl->mutex);
3642
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003643 if (unlikely(wl->state == WL1271_STATE_OFF))
3644 goto out;
3645
Ido Yariva6208652011-03-01 15:14:41 +02003646 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003647 if (ret < 0)
3648 goto out;
3649
3650 ret = wl1271_acx_tsf_info(wl, &mactime);
3651 if (ret < 0)
3652 goto out_sleep;
3653
3654out_sleep:
3655 wl1271_ps_elp_sleep(wl);
3656
3657out:
3658 mutex_unlock(&wl->mutex);
3659 return mactime;
3660}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003661
John W. Linvilleece550d2010-07-28 16:41:06 -04003662static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3663 struct survey_info *survey)
3664{
3665 struct wl1271 *wl = hw->priv;
3666 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003667
John W. Linvilleece550d2010-07-28 16:41:06 -04003668 if (idx != 0)
3669 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003670
John W. Linvilleece550d2010-07-28 16:41:06 -04003671 survey->channel = conf->channel;
3672 survey->filled = SURVEY_INFO_NOISE_DBM;
3673 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003674
John W. Linvilleece550d2010-07-28 16:41:06 -04003675 return 0;
3676}
3677
Arik Nemtsov409622e2011-02-23 00:22:29 +02003678static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003679 struct ieee80211_sta *sta,
3680 u8 *hlid)
3681{
3682 struct wl1271_station *wl_sta;
3683 int id;
3684
3685 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3686 if (id >= AP_MAX_STATIONS) {
3687 wl1271_warning("could not allocate HLID - too much stations");
3688 return -EBUSY;
3689 }
3690
3691 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003692 __set_bit(id, wl->ap_hlid_map);
3693 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3694 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003695 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003696 return 0;
3697}
3698
Arik Nemtsov409622e2011-02-23 00:22:29 +02003699static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003700{
3701 int id = hlid - WL1271_AP_STA_HLID_START;
3702
Arik Nemtsov409622e2011-02-23 00:22:29 +02003703 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3704 return;
3705
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003706 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003707 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003708 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003709 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003710 __clear_bit(hlid, &wl->ap_ps_map);
3711 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003712}
3713
Arik Nemtsov3618f302011-06-26 10:36:03 +03003714bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3715{
3716 int id = hlid - WL1271_AP_STA_HLID_START;
3717 return test_bit(id, wl->ap_hlid_map);
3718}
3719
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003720static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3721 struct ieee80211_vif *vif,
3722 struct ieee80211_sta *sta)
3723{
3724 struct wl1271 *wl = hw->priv;
3725 int ret = 0;
3726 u8 hlid;
3727
3728 mutex_lock(&wl->mutex);
3729
3730 if (unlikely(wl->state == WL1271_STATE_OFF))
3731 goto out;
3732
3733 if (wl->bss_type != BSS_TYPE_AP_BSS)
3734 goto out;
3735
3736 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3737
Arik Nemtsov409622e2011-02-23 00:22:29 +02003738 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003739 if (ret < 0)
3740 goto out;
3741
Ido Yariva6208652011-03-01 15:14:41 +02003742 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003743 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003744 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003745
Eliad Pellerc690ec82011-08-14 13:17:07 +03003746 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003747 if (ret < 0)
3748 goto out_sleep;
3749
Eliad Pellerb67476e2011-08-14 13:17:23 +03003750 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3751 if (ret < 0)
3752 goto out_sleep;
3753
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003754 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3755 if (ret < 0)
3756 goto out_sleep;
3757
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003758out_sleep:
3759 wl1271_ps_elp_sleep(wl);
3760
Arik Nemtsov409622e2011-02-23 00:22:29 +02003761out_free_sta:
3762 if (ret < 0)
3763 wl1271_free_sta(wl, hlid);
3764
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003765out:
3766 mutex_unlock(&wl->mutex);
3767 return ret;
3768}
3769
3770static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3771 struct ieee80211_vif *vif,
3772 struct ieee80211_sta *sta)
3773{
3774 struct wl1271 *wl = hw->priv;
3775 struct wl1271_station *wl_sta;
3776 int ret = 0, id;
3777
3778 mutex_lock(&wl->mutex);
3779
3780 if (unlikely(wl->state == WL1271_STATE_OFF))
3781 goto out;
3782
3783 if (wl->bss_type != BSS_TYPE_AP_BSS)
3784 goto out;
3785
3786 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3787
3788 wl_sta = (struct wl1271_station *)sta->drv_priv;
3789 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3790 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3791 goto out;
3792
Ido Yariva6208652011-03-01 15:14:41 +02003793 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003794 if (ret < 0)
3795 goto out;
3796
Eliad Pellerc690ec82011-08-14 13:17:07 +03003797 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003798 if (ret < 0)
3799 goto out_sleep;
3800
Arik Nemtsov409622e2011-02-23 00:22:29 +02003801 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003802
3803out_sleep:
3804 wl1271_ps_elp_sleep(wl);
3805
3806out:
3807 mutex_unlock(&wl->mutex);
3808 return ret;
3809}
3810
Luciano Coelho4623ec72011-03-21 19:26:41 +02003811static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3812 struct ieee80211_vif *vif,
3813 enum ieee80211_ampdu_mlme_action action,
3814 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3815 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003816{
3817 struct wl1271 *wl = hw->priv;
3818 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003819 u8 hlid, *ba_bitmap;
3820
3821 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3822 tid);
3823
3824 /* sanity check - the fields in FW are only 8bits wide */
3825 if (WARN_ON(tid > 0xFF))
3826 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003827
3828 mutex_lock(&wl->mutex);
3829
3830 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3831 ret = -EAGAIN;
3832 goto out;
3833 }
3834
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003835 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3836 hlid = wl->sta_hlid;
3837 ba_bitmap = &wl->ba_rx_bitmap;
3838 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3839 struct wl1271_station *wl_sta;
3840
3841 wl_sta = (struct wl1271_station *)sta->drv_priv;
3842 hlid = wl_sta->hlid;
3843 ba_bitmap = &wl->links[hlid].ba_bitmap;
3844 } else {
3845 ret = -EINVAL;
3846 goto out;
3847 }
3848
Ido Yariva6208652011-03-01 15:14:41 +02003849 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003850 if (ret < 0)
3851 goto out;
3852
Shahar Levi70559a02011-05-22 16:10:22 +03003853 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3854 tid, action);
3855
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003856 switch (action) {
3857 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003858 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003859 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003860 break;
3861 }
3862
3863 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3864 ret = -EBUSY;
3865 wl1271_error("exceeded max RX BA sessions");
3866 break;
3867 }
3868
3869 if (*ba_bitmap & BIT(tid)) {
3870 ret = -EINVAL;
3871 wl1271_error("cannot enable RX BA session on active "
3872 "tid: %d", tid);
3873 break;
3874 }
3875
3876 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3877 hlid);
3878 if (!ret) {
3879 *ba_bitmap |= BIT(tid);
3880 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003881 }
3882 break;
3883
3884 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003885 if (!(*ba_bitmap & BIT(tid))) {
3886 ret = -EINVAL;
3887 wl1271_error("no active RX BA session on tid: %d",
3888 tid);
3889 break;
3890 }
3891
3892 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3893 hlid);
3894 if (!ret) {
3895 *ba_bitmap &= ~BIT(tid);
3896 wl->ba_rx_session_count--;
3897 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003898 break;
3899
3900 /*
3901 * The BA initiator session management in FW independently.
3902 * Falling break here on purpose for all TX APDU commands.
3903 */
3904 case IEEE80211_AMPDU_TX_START:
3905 case IEEE80211_AMPDU_TX_STOP:
3906 case IEEE80211_AMPDU_TX_OPERATIONAL:
3907 ret = -EINVAL;
3908 break;
3909
3910 default:
3911 wl1271_error("Incorrect ampdu action id=%x\n", action);
3912 ret = -EINVAL;
3913 }
3914
3915 wl1271_ps_elp_sleep(wl);
3916
3917out:
3918 mutex_unlock(&wl->mutex);
3919
3920 return ret;
3921}
3922
Arik Nemtsov33437892011-04-26 23:35:39 +03003923static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3924{
3925 struct wl1271 *wl = hw->priv;
3926 bool ret = false;
3927
3928 mutex_lock(&wl->mutex);
3929
3930 if (unlikely(wl->state == WL1271_STATE_OFF))
3931 goto out;
3932
3933 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003934 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003935
3936 /* the above is appropriate for STA mode for PS purposes */
3937 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3938
3939out:
3940 mutex_unlock(&wl->mutex);
3941
3942 return ret;
3943}
3944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003945/* can't be const, mac80211 writes to this */
3946static struct ieee80211_rate wl1271_rates[] = {
3947 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003948 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3949 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003950 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003951 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3952 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3954 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003955 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3956 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003957 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3958 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003959 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3960 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003961 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3962 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003963 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3964 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003965 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003966 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3967 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003968 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003969 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3970 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003972 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3973 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003974 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003975 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3976 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003977 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003978 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3979 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003980 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003981 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3982 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003983 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003984 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3985 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003986};
3987
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003988/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003989static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003990 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003991 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003992 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3993 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3994 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003995 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003996 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3997 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3998 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003999 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004000 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4001 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4002 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004003 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004004};
4005
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004006/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004007static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004008 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004009 7, /* CONF_HW_RXTX_RATE_MCS7 */
4010 6, /* CONF_HW_RXTX_RATE_MCS6 */
4011 5, /* CONF_HW_RXTX_RATE_MCS5 */
4012 4, /* CONF_HW_RXTX_RATE_MCS4 */
4013 3, /* CONF_HW_RXTX_RATE_MCS3 */
4014 2, /* CONF_HW_RXTX_RATE_MCS2 */
4015 1, /* CONF_HW_RXTX_RATE_MCS1 */
4016 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004017
4018 11, /* CONF_HW_RXTX_RATE_54 */
4019 10, /* CONF_HW_RXTX_RATE_48 */
4020 9, /* CONF_HW_RXTX_RATE_36 */
4021 8, /* CONF_HW_RXTX_RATE_24 */
4022
4023 /* TI-specific rate */
4024 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4025
4026 7, /* CONF_HW_RXTX_RATE_18 */
4027 6, /* CONF_HW_RXTX_RATE_12 */
4028 3, /* CONF_HW_RXTX_RATE_11 */
4029 5, /* CONF_HW_RXTX_RATE_9 */
4030 4, /* CONF_HW_RXTX_RATE_6 */
4031 2, /* CONF_HW_RXTX_RATE_5_5 */
4032 1, /* CONF_HW_RXTX_RATE_2 */
4033 0 /* CONF_HW_RXTX_RATE_1 */
4034};
4035
Shahar Levie8b03a22010-10-13 16:09:39 +02004036/* 11n STA capabilities */
4037#define HW_RX_HIGHEST_RATE 72
4038
Shahar Levi00d20102010-11-08 11:20:10 +00004039#ifdef CONFIG_WL12XX_HT
4040#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004041 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4042 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004043 .ht_supported = true, \
4044 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4045 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4046 .mcs = { \
4047 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4048 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4049 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4050 }, \
4051}
Shahar Levi18357852010-10-13 16:09:41 +02004052#else
Shahar Levi00d20102010-11-08 11:20:10 +00004053#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004054 .ht_supported = false, \
4055}
4056#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004058/* can't be const, mac80211 writes to this */
4059static struct ieee80211_supported_band wl1271_band_2ghz = {
4060 .channels = wl1271_channels,
4061 .n_channels = ARRAY_SIZE(wl1271_channels),
4062 .bitrates = wl1271_rates,
4063 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004064 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004065};
4066
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004067/* 5 GHz data rates for WL1273 */
4068static struct ieee80211_rate wl1271_rates_5ghz[] = {
4069 { .bitrate = 60,
4070 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4071 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4072 { .bitrate = 90,
4073 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4074 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4075 { .bitrate = 120,
4076 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4077 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4078 { .bitrate = 180,
4079 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4080 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4081 { .bitrate = 240,
4082 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4083 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4084 { .bitrate = 360,
4085 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4086 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4087 { .bitrate = 480,
4088 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4089 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4090 { .bitrate = 540,
4091 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4092 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4093};
4094
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004095/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004096static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004097 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4098 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4099 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4100 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4101 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4102 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4103 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4104 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4105 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4106 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4107 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4108 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4109 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4110 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4111 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4112 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4113 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4114 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4115 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4116 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4117 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4118 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4119 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4120 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4121 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4122 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4123 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4124 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4125 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4126 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4127 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4128 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4129 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4130 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004131};
4132
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004133/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004134static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004135 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004136 7, /* CONF_HW_RXTX_RATE_MCS7 */
4137 6, /* CONF_HW_RXTX_RATE_MCS6 */
4138 5, /* CONF_HW_RXTX_RATE_MCS5 */
4139 4, /* CONF_HW_RXTX_RATE_MCS4 */
4140 3, /* CONF_HW_RXTX_RATE_MCS3 */
4141 2, /* CONF_HW_RXTX_RATE_MCS2 */
4142 1, /* CONF_HW_RXTX_RATE_MCS1 */
4143 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004144
4145 7, /* CONF_HW_RXTX_RATE_54 */
4146 6, /* CONF_HW_RXTX_RATE_48 */
4147 5, /* CONF_HW_RXTX_RATE_36 */
4148 4, /* CONF_HW_RXTX_RATE_24 */
4149
4150 /* TI-specific rate */
4151 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4152
4153 3, /* CONF_HW_RXTX_RATE_18 */
4154 2, /* CONF_HW_RXTX_RATE_12 */
4155 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4156 1, /* CONF_HW_RXTX_RATE_9 */
4157 0, /* CONF_HW_RXTX_RATE_6 */
4158 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4159 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4160 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4161};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004162
4163static struct ieee80211_supported_band wl1271_band_5ghz = {
4164 .channels = wl1271_channels_5ghz,
4165 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4166 .bitrates = wl1271_rates_5ghz,
4167 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004168 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004169};
4170
Tobias Klausera0ea9492010-05-20 10:38:11 +02004171static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004172 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4173 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4174};
4175
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004176static const struct ieee80211_ops wl1271_ops = {
4177 .start = wl1271_op_start,
4178 .stop = wl1271_op_stop,
4179 .add_interface = wl1271_op_add_interface,
4180 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004181#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004182 .suspend = wl1271_op_suspend,
4183 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004184#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004185 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004186 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004187 .configure_filter = wl1271_op_configure_filter,
4188 .tx = wl1271_op_tx,
4189 .set_key = wl1271_op_set_key,
4190 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004191 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004192 .sched_scan_start = wl1271_op_sched_scan_start,
4193 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004194 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004195 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004196 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004197 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004198 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004199 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004200 .sta_add = wl1271_op_sta_add,
4201 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004202 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004203 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004204 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004205};
4206
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004207
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004208u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004209{
4210 u8 idx;
4211
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004212 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004213
4214 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4215 wl1271_error("Illegal RX rate from HW: %d", rate);
4216 return 0;
4217 }
4218
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004219 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004220 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4221 wl1271_error("Unsupported RX rate from HW: %d", rate);
4222 return 0;
4223 }
4224
4225 return idx;
4226}
4227
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004228static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4229 struct device_attribute *attr,
4230 char *buf)
4231{
4232 struct wl1271 *wl = dev_get_drvdata(dev);
4233 ssize_t len;
4234
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004235 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004236
4237 mutex_lock(&wl->mutex);
4238 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4239 wl->sg_enabled);
4240 mutex_unlock(&wl->mutex);
4241
4242 return len;
4243
4244}
4245
4246static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4247 struct device_attribute *attr,
4248 const char *buf, size_t count)
4249{
4250 struct wl1271 *wl = dev_get_drvdata(dev);
4251 unsigned long res;
4252 int ret;
4253
Luciano Coelho6277ed62011-04-01 17:49:54 +03004254 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004255 if (ret < 0) {
4256 wl1271_warning("incorrect value written to bt_coex_mode");
4257 return count;
4258 }
4259
4260 mutex_lock(&wl->mutex);
4261
4262 res = !!res;
4263
4264 if (res == wl->sg_enabled)
4265 goto out;
4266
4267 wl->sg_enabled = res;
4268
4269 if (wl->state == WL1271_STATE_OFF)
4270 goto out;
4271
Ido Yariva6208652011-03-01 15:14:41 +02004272 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004273 if (ret < 0)
4274 goto out;
4275
4276 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4277 wl1271_ps_elp_sleep(wl);
4278
4279 out:
4280 mutex_unlock(&wl->mutex);
4281 return count;
4282}
4283
4284static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4285 wl1271_sysfs_show_bt_coex_state,
4286 wl1271_sysfs_store_bt_coex_state);
4287
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004288static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4289 struct device_attribute *attr,
4290 char *buf)
4291{
4292 struct wl1271 *wl = dev_get_drvdata(dev);
4293 ssize_t len;
4294
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004295 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004296
4297 mutex_lock(&wl->mutex);
4298 if (wl->hw_pg_ver >= 0)
4299 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4300 else
4301 len = snprintf(buf, len, "n/a\n");
4302 mutex_unlock(&wl->mutex);
4303
4304 return len;
4305}
4306
Gery Kahn6f07b722011-07-18 14:21:49 +03004307static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004308 wl1271_sysfs_show_hw_pg_ver, NULL);
4309
Ido Yariv95dac04f2011-06-06 14:57:06 +03004310static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4311 struct bin_attribute *bin_attr,
4312 char *buffer, loff_t pos, size_t count)
4313{
4314 struct device *dev = container_of(kobj, struct device, kobj);
4315 struct wl1271 *wl = dev_get_drvdata(dev);
4316 ssize_t len;
4317 int ret;
4318
4319 ret = mutex_lock_interruptible(&wl->mutex);
4320 if (ret < 0)
4321 return -ERESTARTSYS;
4322
4323 /* Let only one thread read the log at a time, blocking others */
4324 while (wl->fwlog_size == 0) {
4325 DEFINE_WAIT(wait);
4326
4327 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4328 &wait,
4329 TASK_INTERRUPTIBLE);
4330
4331 if (wl->fwlog_size != 0) {
4332 finish_wait(&wl->fwlog_waitq, &wait);
4333 break;
4334 }
4335
4336 mutex_unlock(&wl->mutex);
4337
4338 schedule();
4339 finish_wait(&wl->fwlog_waitq, &wait);
4340
4341 if (signal_pending(current))
4342 return -ERESTARTSYS;
4343
4344 ret = mutex_lock_interruptible(&wl->mutex);
4345 if (ret < 0)
4346 return -ERESTARTSYS;
4347 }
4348
4349 /* Check if the fwlog is still valid */
4350 if (wl->fwlog_size < 0) {
4351 mutex_unlock(&wl->mutex);
4352 return 0;
4353 }
4354
4355 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4356 len = min(count, (size_t)wl->fwlog_size);
4357 wl->fwlog_size -= len;
4358 memcpy(buffer, wl->fwlog, len);
4359
4360 /* Make room for new messages */
4361 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4362
4363 mutex_unlock(&wl->mutex);
4364
4365 return len;
4366}
4367
4368static struct bin_attribute fwlog_attr = {
4369 .attr = {.name = "fwlog", .mode = S_IRUSR},
4370 .read = wl1271_sysfs_read_fwlog,
4371};
4372
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004373int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004374{
4375 int ret;
4376
4377 if (wl->mac80211_registered)
4378 return 0;
4379
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004380 ret = wl1271_fetch_nvs(wl);
4381 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004382 /* NOTE: The wl->nvs->nvs element must be first, in
4383 * order to simplify the casting, we assume it is at
4384 * the beginning of the wl->nvs structure.
4385 */
4386 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004387
4388 wl->mac_addr[0] = nvs_ptr[11];
4389 wl->mac_addr[1] = nvs_ptr[10];
4390 wl->mac_addr[2] = nvs_ptr[6];
4391 wl->mac_addr[3] = nvs_ptr[5];
4392 wl->mac_addr[4] = nvs_ptr[4];
4393 wl->mac_addr[5] = nvs_ptr[3];
4394 }
4395
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004396 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4397
4398 ret = ieee80211_register_hw(wl->hw);
4399 if (ret < 0) {
4400 wl1271_error("unable to register mac80211 hw: %d", ret);
4401 return ret;
4402 }
4403
4404 wl->mac80211_registered = true;
4405
Eliad Pellerd60080a2010-11-24 12:53:16 +02004406 wl1271_debugfs_init(wl);
4407
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004408 register_netdevice_notifier(&wl1271_dev_notifier);
4409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410 wl1271_notice("loaded");
4411
4412 return 0;
4413}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004414EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004416void wl1271_unregister_hw(struct wl1271 *wl)
4417{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004418 if (wl->state == WL1271_STATE_PLT)
4419 __wl1271_plt_stop(wl);
4420
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004421 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004422 ieee80211_unregister_hw(wl->hw);
4423 wl->mac80211_registered = false;
4424
4425}
4426EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4427
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004428int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004430 static const u32 cipher_suites[] = {
4431 WLAN_CIPHER_SUITE_WEP40,
4432 WLAN_CIPHER_SUITE_WEP104,
4433 WLAN_CIPHER_SUITE_TKIP,
4434 WLAN_CIPHER_SUITE_CCMP,
4435 WL1271_CIPHER_SUITE_GEM,
4436 };
4437
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004438 /* The tx descriptor buffer and the TKIP space. */
4439 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4440 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441
4442 /* unit us */
4443 /* FIXME: find a proper value */
4444 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004445 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446
4447 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004448 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004449 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004450 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004451 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004452 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004453 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004454 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004455 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004456 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004458 wl->hw->wiphy->cipher_suites = cipher_suites;
4459 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4460
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004461 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004462 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004463 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004464 /*
4465 * Maximum length of elements in scanning probe request templates
4466 * should be the maximum length possible for a template, without
4467 * the IEEE80211 header of the template
4468 */
Eliad Peller154037d2011-08-14 13:17:12 +03004469 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004470 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004471
Luciano Coelho4a31c112011-03-21 23:16:14 +02004472 /* make sure all our channels fit in the scanned_ch bitmask */
4473 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4474 ARRAY_SIZE(wl1271_channels_5ghz) >
4475 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004476 /*
4477 * We keep local copies of the band structs because we need to
4478 * modify them on a per-device basis.
4479 */
4480 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4481 sizeof(wl1271_band_2ghz));
4482 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4483 sizeof(wl1271_band_5ghz));
4484
4485 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4486 &wl->bands[IEEE80211_BAND_2GHZ];
4487 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4488 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004489
Kalle Valo12bd8942010-03-18 12:26:33 +02004490 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004491 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004492
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004493 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4494
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004495 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004496
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004497 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4498
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004499 wl->hw->max_rx_aggregation_subframes = 8;
4500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501 return 0;
4502}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004503EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004504
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004505#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004506
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004507struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004508{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004509 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004510 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004511 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004512 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004513 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004514
4515 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4516 if (!hw) {
4517 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004518 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004519 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004520 }
4521
Julia Lawall929ebd32010-05-15 23:16:39 +02004522 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004523 if (!plat_dev) {
4524 wl1271_error("could not allocate platform_device");
4525 ret = -ENOMEM;
4526 goto err_plat_alloc;
4527 }
4528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004529 wl = hw->priv;
4530 memset(wl, 0, sizeof(*wl));
4531
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004532 INIT_LIST_HEAD(&wl->list);
4533
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004534 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004535 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004536
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004537 for (i = 0; i < NUM_TX_QUEUES; i++)
4538 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004540 for (i = 0; i < NUM_TX_QUEUES; i++)
4541 for (j = 0; j < AP_MAX_LINKS; j++)
4542 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4543
Ido Yariva6208652011-03-01 15:14:41 +02004544 skb_queue_head_init(&wl->deferred_rx_queue);
4545 skb_queue_head_init(&wl->deferred_tx_queue);
4546
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004547 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004548 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004549 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004550 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4551 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4552 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004553 INIT_WORK(&wl->rx_streaming_enable_work,
4554 wl1271_rx_streaming_enable_work);
4555 INIT_WORK(&wl->rx_streaming_disable_work,
4556 wl1271_rx_streaming_disable_work);
4557
Eliad Peller92ef8962011-06-07 12:50:46 +03004558 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4559 if (!wl->freezable_wq) {
4560 ret = -ENOMEM;
4561 goto err_hw;
4562 }
4563
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004564 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004565 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004566 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004567 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004568 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004569 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004570 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004571 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004572 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004573 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004574 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004575 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004576 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004577 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004578 wl->bss_type = MAX_BSS_TYPE;
4579 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004580 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004581 wl->ap_ps_map = 0;
4582 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004583 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004584 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004585 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004586 wl->tx_security_seq = 0;
4587 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004588 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004589 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004590 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004591 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4592 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004593 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004594 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4595 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004596 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4597 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004598 wl->fwlog_size = 0;
4599 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004600
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004601 /* The system link is always allocated */
4602 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4603
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004604 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004605 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004606 wl->tx_frames[i] = NULL;
4607
4608 spin_lock_init(&wl->wl_lock);
4609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004610 wl->state = WL1271_STATE_OFF;
4611 mutex_init(&wl->mutex);
4612
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004613 /* Apply default driver configuration. */
4614 wl1271_conf_init(wl);
4615
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004616 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4617 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4618 if (!wl->aggr_buf) {
4619 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004620 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004621 }
4622
Ido Yariv990f5de2011-03-31 10:06:59 +02004623 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4624 if (!wl->dummy_packet) {
4625 ret = -ENOMEM;
4626 goto err_aggr;
4627 }
4628
Ido Yariv95dac04f2011-06-06 14:57:06 +03004629 /* Allocate one page for the FW log */
4630 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4631 if (!wl->fwlog) {
4632 ret = -ENOMEM;
4633 goto err_dummy_packet;
4634 }
4635
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004636 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004637 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004638 if (ret) {
4639 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004640 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004641 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004642 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004643
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004644 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004645 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004646 if (ret < 0) {
4647 wl1271_error("failed to create sysfs file bt_coex_state");
4648 goto err_platform;
4649 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004650
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004651 /* Create sysfs file to get HW PG version */
4652 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4653 if (ret < 0) {
4654 wl1271_error("failed to create sysfs file hw_pg_ver");
4655 goto err_bt_coex_state;
4656 }
4657
Ido Yariv95dac04f2011-06-06 14:57:06 +03004658 /* Create sysfs file for the FW log */
4659 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4660 if (ret < 0) {
4661 wl1271_error("failed to create sysfs file fwlog");
4662 goto err_hw_pg_ver;
4663 }
4664
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004665 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004666
Ido Yariv95dac04f2011-06-06 14:57:06 +03004667err_hw_pg_ver:
4668 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4669
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004670err_bt_coex_state:
4671 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4672
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004673err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004674 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004675
Ido Yariv95dac04f2011-06-06 14:57:06 +03004676err_fwlog:
4677 free_page((unsigned long)wl->fwlog);
4678
Ido Yariv990f5de2011-03-31 10:06:59 +02004679err_dummy_packet:
4680 dev_kfree_skb(wl->dummy_packet);
4681
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004682err_aggr:
4683 free_pages((unsigned long)wl->aggr_buf, order);
4684
Eliad Peller92ef8962011-06-07 12:50:46 +03004685err_wq:
4686 destroy_workqueue(wl->freezable_wq);
4687
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004688err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004689 wl1271_debugfs_exit(wl);
4690 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004691
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004692err_plat_alloc:
4693 ieee80211_free_hw(hw);
4694
4695err_hw_alloc:
4696
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004697 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004698}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004699EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004700
4701int wl1271_free_hw(struct wl1271 *wl)
4702{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004703 /* Unblock any fwlog readers */
4704 mutex_lock(&wl->mutex);
4705 wl->fwlog_size = -1;
4706 wake_up_interruptible_all(&wl->fwlog_waitq);
4707 mutex_unlock(&wl->mutex);
4708
4709 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004710
4711 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4712
4713 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004714 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004715 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004716 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004717 free_pages((unsigned long)wl->aggr_buf,
4718 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004719 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004720
4721 wl1271_debugfs_exit(wl);
4722
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004723 vfree(wl->fw);
4724 wl->fw = NULL;
4725 kfree(wl->nvs);
4726 wl->nvs = NULL;
4727
4728 kfree(wl->fw_status);
4729 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004730 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004731
4732 ieee80211_free_hw(wl->hw);
4733
4734 return 0;
4735}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004736EXPORT_SYMBOL_GPL(wl1271_free_hw);
4737
Guy Eilam491bbd62011-01-12 10:33:29 +01004738u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004739EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004740module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004741MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4742
Ido Yariv95dac04f2011-06-06 14:57:06 +03004743module_param_named(fwlog, fwlog_param, charp, 0);
4744MODULE_PARM_DESC(keymap,
4745 "FW logger options: continuous, ondemand, dbgpins or disable");
4746
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004747MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004748MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004749MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");