blob: 09cecb336d5398f59ddcf78f38db3424657b12b6 [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 */
830 wl->tx_allocated_pkts -=
831 (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
Eliad Peller4d56ad92011-08-14 13:17:05 +0300837 freed_blocks = le32_to_cpu(status->total_released_blks) -
838 wl->tx_blocks_freed;
839 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200840
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300841 wl->tx_allocated_blocks -= freed_blocks;
842
Eliad Peller4d56ad92011-08-14 13:17:05 +0300843 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200844
Eliad Peller4d56ad92011-08-14 13:17:05 +0300845 /*
846 * The FW might change the total number of TX memblocks before
847 * we get a notification about blocks being released. Thus, the
848 * available blocks calculation might yield a temporary result
849 * which is lower than the actual available blocks. Keeping in
850 * mind that only blocks that were allocated can be moved from
851 * TX to RX, tx_blocks_available should never decrease here.
852 */
853 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
854 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300855
Ido Yariva5225502010-10-12 14:49:10 +0200856 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200857 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200858 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859
Eliad Peller4d56ad92011-08-14 13:17:05 +0300860 /* for AP update num of allocated TX blocks per link and ps status */
861 if (wl->bss_type == BSS_TYPE_AP_BSS) {
862#if 0
863 wl1271_irq_update_links_status(wl, status);
864#endif
865 }
866
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200868 getnstimeofday(&ts);
869 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
870 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871}
872
Ido Yariva6208652011-03-01 15:14:41 +0200873static void wl1271_flush_deferred_work(struct wl1271 *wl)
874{
875 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200876
Ido Yariva6208652011-03-01 15:14:41 +0200877 /* Pass all received frames to the network stack */
878 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
879 ieee80211_rx_ni(wl->hw, skb);
880
881 /* Return sent skbs to the network stack */
882 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300883 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200884}
885
886static void wl1271_netstack_work(struct work_struct *work)
887{
888 struct wl1271 *wl =
889 container_of(work, struct wl1271, netstack_work);
890
891 do {
892 wl1271_flush_deferred_work(wl);
893 } while (skb_queue_len(&wl->deferred_rx_queue));
894}
895
896#define WL1271_IRQ_MAX_LOOPS 256
897
898irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300901 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200902 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200903 struct wl1271 *wl = (struct wl1271 *)cookie;
904 bool done = false;
905 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200906 unsigned long flags;
907
908 /* TX might be handled here, avoid redundant work */
909 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
910 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
Ido Yariv341b7cd2011-03-31 10:07:01 +0200912 /*
913 * In case edge triggered interrupt must be used, we cannot iterate
914 * more than once without introducing race conditions with the hardirq.
915 */
916 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
917 loopcount = 1;
918
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 mutex_lock(&wl->mutex);
920
921 wl1271_debug(DEBUG_IRQ, "IRQ work");
922
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200923 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924 goto out;
925
Ido Yariva6208652011-03-01 15:14:41 +0200926 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 if (ret < 0)
928 goto out;
929
Ido Yariva6208652011-03-01 15:14:41 +0200930 while (!done && loopcount--) {
931 /*
932 * In order to avoid a race with the hardirq, clear the flag
933 * before acknowledging the chip. Since the mutex is held,
934 * wl1271_ps_elp_wakeup cannot be called concurrently.
935 */
936 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
937 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200938
Eliad Peller4d56ad92011-08-14 13:17:05 +0300939 wl12xx_fw_status(wl, wl->fw_status);
940 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200941 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200942 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200943 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200944 continue;
945 }
946
Eliad Pellerccc83b02010-10-27 14:09:57 +0200947 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
948 wl1271_error("watchdog interrupt received! "
949 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300950 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200951
952 /* restarting the chip. ignore any other interrupt. */
953 goto out;
954 }
955
Ido Yariva6208652011-03-01 15:14:41 +0200956 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200957 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
958
Eliad Peller4d56ad92011-08-14 13:17:05 +0300959 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960
Ido Yariva5225502010-10-12 14:49:10 +0200961 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200962 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200963 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300964 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200965 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200966 /*
967 * In order to avoid starvation of the TX path,
968 * call the work function directly.
969 */
970 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200971 } else {
972 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200973 }
974
Ido Yariv8aad2462011-03-01 15:14:38 +0200975 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300976 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200977 (wl->tx_results_count & 0xff))
978 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200979
980 /* Make sure the deferred queues don't get too long */
981 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
982 skb_queue_len(&wl->deferred_rx_queue);
983 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
984 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200985 }
986
987 if (intr & WL1271_ACX_INTR_EVENT_A) {
988 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
989 wl1271_event_handle(wl, 0);
990 }
991
992 if (intr & WL1271_ACX_INTR_EVENT_B) {
993 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
994 wl1271_event_handle(wl, 1);
995 }
996
997 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
998 wl1271_debug(DEBUG_IRQ,
999 "WL1271_ACX_INTR_INIT_COMPLETE");
1000
1001 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1002 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003 }
1004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 wl1271_ps_elp_sleep(wl);
1006
1007out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001008 spin_lock_irqsave(&wl->wl_lock, flags);
1009 /* In case TX was not handled here, queue TX work */
1010 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1011 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001012 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001013 ieee80211_queue_work(wl->hw, &wl->tx_work);
1014 spin_unlock_irqrestore(&wl->wl_lock, flags);
1015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001017
1018 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019}
Ido Yariva6208652011-03-01 15:14:41 +02001020EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022static int wl1271_fetch_firmware(struct wl1271 *wl)
1023{
1024 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001025 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 int ret;
1027
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001028 if (wl->chip.id == CHIP_ID_1283_PG20)
1029 fw_name = WL128X_FW_NAME;
1030 else
1031 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001032
1033 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1034
1035 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036
1037 if (ret < 0) {
1038 wl1271_error("could not get firmware: %d", ret);
1039 return ret;
1040 }
1041
1042 if (fw->size % 4) {
1043 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1044 fw->size);
1045 ret = -EILSEQ;
1046 goto out;
1047 }
1048
Arik Nemtsov166d5042010-10-16 21:44:57 +02001049 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001051 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
1053 if (!wl->fw) {
1054 wl1271_error("could not allocate memory for the firmware");
1055 ret = -ENOMEM;
1056 goto out;
1057 }
1058
1059 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060 ret = 0;
1061
1062out:
1063 release_firmware(fw);
1064
1065 return ret;
1066}
1067
1068static int wl1271_fetch_nvs(struct wl1271 *wl)
1069{
1070 const struct firmware *fw;
1071 int ret;
1072
Shahar Levi5aa42342011-03-06 16:32:07 +02001073 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074
1075 if (ret < 0) {
1076 wl1271_error("could not get nvs file: %d", ret);
1077 return ret;
1078 }
1079
Shahar Levibc765bf2011-03-06 16:32:10 +02001080 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
1082 if (!wl->nvs) {
1083 wl1271_error("could not allocate memory for the nvs file");
1084 ret = -ENOMEM;
1085 goto out;
1086 }
1087
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001088 wl->nvs_len = fw->size;
1089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090out:
1091 release_firmware(fw);
1092
1093 return ret;
1094}
1095
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001096void wl12xx_queue_recovery_work(struct wl1271 *wl)
1097{
1098 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1099 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1100}
1101
Ido Yariv95dac04f2011-06-06 14:57:06 +03001102size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1103{
1104 size_t len = 0;
1105
1106 /* The FW log is a length-value list, find where the log end */
1107 while (len < maxlen) {
1108 if (memblock[len] == 0)
1109 break;
1110 if (len + memblock[len] + 1 > maxlen)
1111 break;
1112 len += memblock[len] + 1;
1113 }
1114
1115 /* Make sure we have enough room */
1116 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1117
1118 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1119 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1120 wl->fwlog_size += len;
1121
1122 return len;
1123}
1124
1125static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1126{
1127 u32 addr;
1128 u32 first_addr;
1129 u8 *block;
1130
1131 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1132 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1133 (wl->conf.fwlog.mem_blocks == 0))
1134 return;
1135
1136 wl1271_info("Reading FW panic log");
1137
1138 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1139 if (!block)
1140 return;
1141
1142 /*
1143 * Make sure the chip is awake and the logger isn't active.
1144 * This might fail if the firmware hanged.
1145 */
1146 if (!wl1271_ps_elp_wakeup(wl))
1147 wl12xx_cmd_stop_fwlog(wl);
1148
1149 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001150 wl12xx_fw_status(wl, wl->fw_status);
1151 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001152 if (!first_addr)
1153 goto out;
1154
1155 /* Traverse the memory blocks linked list */
1156 addr = first_addr;
1157 do {
1158 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1159 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1160 false);
1161
1162 /*
1163 * Memory blocks are linked to one another. The first 4 bytes
1164 * of each memory block hold the hardware address of the next
1165 * one. The last memory block points to the first one.
1166 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001167 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001168 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1169 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1170 break;
1171 } while (addr && (addr != first_addr));
1172
1173 wake_up_interruptible(&wl->fwlog_waitq);
1174
1175out:
1176 kfree(block);
1177}
1178
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001179static void wl1271_recovery_work(struct work_struct *work)
1180{
1181 struct wl1271 *wl =
1182 container_of(work, struct wl1271, recovery_work);
1183
1184 mutex_lock(&wl->mutex);
1185
1186 if (wl->state != WL1271_STATE_ON)
1187 goto out;
1188
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001189 /* Avoid a recursive recovery */
1190 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1191
Ido Yariv95dac04f2011-06-06 14:57:06 +03001192 wl12xx_read_fwlog_panic(wl);
1193
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001194 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1195 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001196
Oz Krakowskib992c682011-06-26 10:36:02 +03001197 /*
1198 * Advance security sequence number to overcome potential progress
1199 * in the firmware during recovery. This doens't hurt if the network is
1200 * not encrypted.
1201 */
1202 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1203 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1204 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1205
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001206 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1207 ieee80211_connection_loss(wl->vif);
1208
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001209 /* Prevent spurious TX during FW restart */
1210 ieee80211_stop_queues(wl->hw);
1211
Luciano Coelho33c2c062011-05-10 14:46:02 +03001212 if (wl->sched_scanning) {
1213 ieee80211_sched_scan_stopped(wl->hw);
1214 wl->sched_scanning = false;
1215 }
1216
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001217 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001218 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001219
1220 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1221
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001222 ieee80211_restart_hw(wl->hw);
1223
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001224 /*
1225 * Its safe to enable TX now - the queues are stopped after a request
1226 * to restart the HW.
1227 */
1228 ieee80211_wake_queues(wl->hw);
1229
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001230out:
1231 mutex_unlock(&wl->mutex);
1232}
1233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234static void wl1271_fw_wakeup(struct wl1271 *wl)
1235{
1236 u32 elp_reg;
1237
1238 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001239 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240}
1241
1242static int wl1271_setup(struct wl1271 *wl)
1243{
1244 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1245 if (!wl->fw_status)
1246 return -ENOMEM;
1247
1248 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1249 if (!wl->tx_res_if) {
1250 kfree(wl->fw_status);
1251 return -ENOMEM;
1252 }
1253
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 return 0;
1255}
1256
1257static int wl1271_chip_wakeup(struct wl1271 *wl)
1258{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001259 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260 int ret = 0;
1261
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001262 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001263 ret = wl1271_power_on(wl);
1264 if (ret < 0)
1265 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001267 wl1271_io_reset(wl);
1268 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
1270 /* We don't need a real memory partition here, because we only want
1271 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001272 memset(&partition, 0, sizeof(partition));
1273 partition.reg.start = REGISTERS_BASE;
1274 partition.reg.size = REGISTERS_DOWN_SIZE;
1275 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276
1277 /* ELP module wake up */
1278 wl1271_fw_wakeup(wl);
1279
1280 /* whal_FwCtrl_BootSm() */
1281
1282 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001283 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284
1285 /* 1. check if chip id is valid */
1286
1287 switch (wl->chip.id) {
1288 case CHIP_ID_1271_PG10:
1289 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1290 wl->chip.id);
1291
1292 ret = wl1271_setup(wl);
1293 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001294 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295 break;
1296 case CHIP_ID_1271_PG20:
1297 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1298 wl->chip.id);
1299
Shahar Levi0c005042011-06-12 10:34:43 +03001300 /*
1301 * 'end-of-transaction flag' and 'LPD mode flag'
1302 * should be set in wl127x AP mode only
1303 */
Shahar Levi564f5952011-04-04 10:20:39 +03001304 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001305 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1306 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001307
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 ret = wl1271_setup(wl);
1309 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001310 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001312 case CHIP_ID_1283_PG20:
1313 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1314 wl->chip.id);
1315
1316 ret = wl1271_setup(wl);
1317 if (ret < 0)
1318 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001319
Ido Yariv0da13da2011-03-31 10:06:58 +02001320 if (wl1271_set_block_size(wl))
1321 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001322 break;
1323 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 }
1329
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001330 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 ret = wl1271_fetch_firmware(wl);
1332 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 }
1335
1336 /* No NVS from netlink, try to get it from the filesystem */
1337 if (wl->nvs == NULL) {
1338 ret = wl1271_fetch_nvs(wl);
1339 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001340 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 }
1342
1343out:
1344 return ret;
1345}
1346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347int wl1271_plt_start(struct wl1271 *wl)
1348{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001349 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001350 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 int ret;
1352
1353 mutex_lock(&wl->mutex);
1354
1355 wl1271_notice("power up");
1356
1357 if (wl->state != WL1271_STATE_OFF) {
1358 wl1271_error("cannot go into PLT state because not "
1359 "in off state: %d", wl->state);
1360 ret = -EBUSY;
1361 goto out;
1362 }
1363
Arik Nemtsov166d5042010-10-16 21:44:57 +02001364 wl->bss_type = BSS_TYPE_STA_BSS;
1365
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 while (retries) {
1367 retries--;
1368 ret = wl1271_chip_wakeup(wl);
1369 if (ret < 0)
1370 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001372 ret = wl1271_boot(wl);
1373 if (ret < 0)
1374 goto power_off;
1375
1376 ret = wl1271_plt_init(wl);
1377 if (ret < 0)
1378 goto irq_disable;
1379
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001380 wl->state = WL1271_STATE_PLT;
1381 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001382 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001383
Gery Kahn6f07b722011-07-18 14:21:49 +03001384 /* update hw/fw version info in wiphy struct */
1385 wiphy->hw_version = wl->chip.id;
1386 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1387 sizeof(wiphy->fw_version));
1388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 goto out;
1390
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001392 mutex_unlock(&wl->mutex);
1393 /* Unlocking the mutex in the middle of handling is
1394 inherently unsafe. In this case we deem it safe to do,
1395 because we need to let any possibly pending IRQ out of
1396 the system (and while we are WL1271_STATE_OFF the IRQ
1397 work function will not do anything.) Also, any other
1398 possible concurrent operations will fail due to the
1399 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001400 wl1271_disable_interrupts(wl);
1401 wl1271_flush_deferred_work(wl);
1402 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 mutex_lock(&wl->mutex);
1404power_off:
1405 wl1271_power_off(wl);
1406 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1409 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410out:
1411 mutex_unlock(&wl->mutex);
1412
1413 return ret;
1414}
1415
Luciano Coelho4623ec72011-03-21 19:26:41 +02001416static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417{
1418 int ret = 0;
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 wl1271_notice("power down");
1421
1422 if (wl->state != WL1271_STATE_PLT) {
1423 wl1271_error("cannot power down because not in PLT "
1424 "state: %d", wl->state);
1425 ret = -EBUSY;
1426 goto out;
1427 }
1428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 wl1271_power_off(wl);
1430
1431 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001432 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001434 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001435 wl1271_disable_interrupts(wl);
1436 wl1271_flush_deferred_work(wl);
1437 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001438 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001439 mutex_lock(&wl->mutex);
1440out:
1441 return ret;
1442}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001443
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001444int wl1271_plt_stop(struct wl1271 *wl)
1445{
1446 int ret;
1447
1448 mutex_lock(&wl->mutex);
1449 ret = __wl1271_plt_stop(wl);
1450 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 return ret;
1452}
1453
Johannes Berg7bb45682011-02-24 14:42:06 +01001454static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455{
1456 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001457 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001458 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001459 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001461 mapping = skb_get_queue_mapping(skb);
1462 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001463
1464 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001465 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001466
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001467 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001468
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001469 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001470
1471 /*
1472 * The workqueue is slow to process the tx_queue and we need stop
1473 * the queue here, otherwise the queue will get too long.
1474 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001475 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001476 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1477 ieee80211_stop_queue(wl->hw, mapping);
1478 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001479 }
1480
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001481 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001482 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001483 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1484 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1485 } else {
1486 skb_queue_tail(&wl->tx_queue[q], skb);
1487 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488
1489 /*
1490 * The chip specific setup must run before the first TX packet -
1491 * before that, the tx_work will not be initialized!
1492 */
1493
Ido Yarivb07d4032011-03-01 15:14:43 +02001494 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1495 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001496 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001497
1498 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499}
1500
Shahar Leviae47c452011-03-06 16:32:14 +02001501int wl1271_tx_dummy_packet(struct wl1271 *wl)
1502{
Ido Yariv990f5de2011-03-31 10:06:59 +02001503 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001504 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001505
Ido Yariv990f5de2011-03-31 10:06:59 +02001506 spin_lock_irqsave(&wl->wl_lock, flags);
1507 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001508 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001509 spin_unlock_irqrestore(&wl->wl_lock, flags);
1510
1511 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1512 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1513 wl1271_tx_work_locked(wl);
1514
1515 /*
1516 * If the FW TX is busy, TX work will be scheduled by the threaded
1517 * interrupt handler function
1518 */
1519 return 0;
1520}
1521
1522/*
1523 * The size of the dummy packet should be at least 1400 bytes. However, in
1524 * order to minimize the number of bus transactions, aligning it to 512 bytes
1525 * boundaries could be beneficial, performance wise
1526 */
1527#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1528
Luciano Coelhocf27d862011-04-01 21:08:23 +03001529static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001530{
1531 struct sk_buff *skb;
1532 struct ieee80211_hdr_3addr *hdr;
1533 unsigned int dummy_packet_size;
1534
1535 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1536 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1537
1538 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001539 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001540 wl1271_warning("Failed to allocate a dummy packet skb");
1541 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001542 }
1543
1544 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1545
1546 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1547 memset(hdr, 0, sizeof(*hdr));
1548 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001549 IEEE80211_STYPE_NULLFUNC |
1550 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001551
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001554 /* Dummy packets require the TID to be management */
1555 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001556
1557 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001558 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001560
Ido Yariv990f5de2011-03-31 10:06:59 +02001561 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001562}
1563
Ido Yariv990f5de2011-03-31 10:06:59 +02001564
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001565static struct notifier_block wl1271_dev_notifier = {
1566 .notifier_call = wl1271_dev_notify,
1567};
1568
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001569#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001570static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001571{
Eliad Pellere85d1622011-06-27 13:06:43 +03001572 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001573
Eliad Peller94390642011-05-13 11:57:13 +03001574 mutex_lock(&wl->mutex);
1575
Eliad Pellere85d1622011-06-27 13:06:43 +03001576 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1577 goto out_unlock;
1578
Eliad Peller94390642011-05-13 11:57:13 +03001579 ret = wl1271_ps_elp_wakeup(wl);
1580 if (ret < 0)
1581 goto out_unlock;
1582
1583 /* enter psm if needed*/
1584 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1585 DECLARE_COMPLETION_ONSTACK(compl);
1586
1587 wl->ps_compl = &compl;
1588 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1589 wl->basic_rate, true);
1590 if (ret < 0)
1591 goto out_sleep;
1592
1593 /* we must unlock here so we will be able to get events */
1594 wl1271_ps_elp_sleep(wl);
1595 mutex_unlock(&wl->mutex);
1596
1597 ret = wait_for_completion_timeout(
1598 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1599 if (ret <= 0) {
1600 wl1271_warning("couldn't enter ps mode!");
1601 ret = -EBUSY;
1602 goto out;
1603 }
1604
1605 /* take mutex again, and wakeup */
1606 mutex_lock(&wl->mutex);
1607
1608 ret = wl1271_ps_elp_wakeup(wl);
1609 if (ret < 0)
1610 goto out_unlock;
1611 }
1612out_sleep:
1613 wl1271_ps_elp_sleep(wl);
1614out_unlock:
1615 mutex_unlock(&wl->mutex);
1616out:
1617 return ret;
1618
1619}
1620
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001621static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001622{
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001624
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625 mutex_lock(&wl->mutex);
1626
Eliad Pellere85d1622011-06-27 13:06:43 +03001627 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1628 goto out_unlock;
1629
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630 ret = wl1271_ps_elp_wakeup(wl);
1631 if (ret < 0)
1632 goto out_unlock;
1633
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001634 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635
1636 wl1271_ps_elp_sleep(wl);
1637out_unlock:
1638 mutex_unlock(&wl->mutex);
1639 return ret;
1640
1641}
1642
1643static int wl1271_configure_suspend(struct wl1271 *wl)
1644{
1645 if (wl->bss_type == BSS_TYPE_STA_BSS)
1646 return wl1271_configure_suspend_sta(wl);
1647 if (wl->bss_type == BSS_TYPE_AP_BSS)
1648 return wl1271_configure_suspend_ap(wl);
1649 return 0;
1650}
1651
1652static void wl1271_configure_resume(struct wl1271 *wl)
1653{
1654 int ret;
1655 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1656 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1657
1658 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001659 return;
1660
1661 mutex_lock(&wl->mutex);
1662 ret = wl1271_ps_elp_wakeup(wl);
1663 if (ret < 0)
1664 goto out;
1665
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001666 if (is_sta) {
1667 /* exit psm if it wasn't configured */
1668 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1669 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1670 wl->basic_rate, true);
1671 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001672 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 }
Eliad Peller94390642011-05-13 11:57:13 +03001674
1675 wl1271_ps_elp_sleep(wl);
1676out:
1677 mutex_unlock(&wl->mutex);
1678}
1679
Eliad Peller402e48612011-05-13 11:57:09 +03001680static int wl1271_op_suspend(struct ieee80211_hw *hw,
1681 struct cfg80211_wowlan *wow)
1682{
1683 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001684 int ret;
1685
Eliad Peller402e48612011-05-13 11:57:09 +03001686 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001687 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001688
Eliad Peller4a859df2011-06-06 12:21:52 +03001689 wl->wow_enabled = true;
1690 ret = wl1271_configure_suspend(wl);
1691 if (ret < 0) {
1692 wl1271_warning("couldn't prepare device to suspend");
1693 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 /* flush any remaining work */
1696 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001697
1698 /*
1699 * disable and re-enable interrupts in order to flush
1700 * the threaded_irq
1701 */
1702 wl1271_disable_interrupts(wl);
1703
1704 /*
1705 * set suspended flag to avoid triggering a new threaded_irq
1706 * work. no need for spinlock as interrupts are disabled.
1707 */
1708 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1709
1710 wl1271_enable_interrupts(wl);
1711 flush_work(&wl->tx_work);
1712 flush_delayed_work(&wl->pspoll_work);
1713 flush_delayed_work(&wl->elp_work);
1714
Eliad Peller402e48612011-05-13 11:57:09 +03001715 return 0;
1716}
1717
1718static int wl1271_op_resume(struct ieee80211_hw *hw)
1719{
1720 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001721 unsigned long flags;
1722 bool run_irq_work = false;
1723
Eliad Peller402e48612011-05-13 11:57:09 +03001724 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1725 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001727
1728 /*
1729 * re-enable irq_work enqueuing, and call irq_work directly if
1730 * there is a pending work.
1731 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 spin_lock_irqsave(&wl->wl_lock, flags);
1733 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1734 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1735 run_irq_work = true;
1736 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001737
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 if (run_irq_work) {
1739 wl1271_debug(DEBUG_MAC80211,
1740 "run postponed irq_work directly");
1741 wl1271_irq(0, wl);
1742 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001743 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001744 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001745 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746
Eliad Peller402e48612011-05-13 11:57:09 +03001747 return 0;
1748}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001749#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001750
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751static int wl1271_op_start(struct ieee80211_hw *hw)
1752{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001753 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1754
1755 /*
1756 * We have to delay the booting of the hardware because
1757 * we need to know the local MAC address before downloading and
1758 * initializing the firmware. The MAC address cannot be changed
1759 * after boot, and without the proper MAC address, the firmware
1760 * will not function properly.
1761 *
1762 * The MAC address is first known when the corresponding interface
1763 * is added. That is where we will initialize the hardware.
1764 */
1765
1766 return 0;
1767}
1768
1769static void wl1271_op_stop(struct ieee80211_hw *hw)
1770{
1771 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1772}
1773
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001774static u8 wl12xx_get_role_type(struct wl1271 *wl)
1775{
1776 switch (wl->bss_type) {
1777 case BSS_TYPE_AP_BSS:
1778 return WL1271_ROLE_AP;
1779
1780 case BSS_TYPE_STA_BSS:
1781 return WL1271_ROLE_STA;
1782
Eliad Peller227e81e2011-08-14 13:17:26 +03001783 case BSS_TYPE_IBSS:
1784 return WL1271_ROLE_IBSS;
1785
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001786 default:
1787 wl1271_error("invalid bss_type: %d", wl->bss_type);
1788 }
1789 return WL12XX_INVALID_ROLE_TYPE;
1790}
1791
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001792static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1793 struct ieee80211_vif *vif)
1794{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001796 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001797 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001799 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001800 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001802 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1803 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804
1805 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001806 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001807 wl1271_debug(DEBUG_MAC80211,
1808 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001809 ret = -EBUSY;
1810 goto out;
1811 }
1812
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001813 /*
1814 * in some very corner case HW recovery scenarios its possible to
1815 * get here before __wl1271_op_remove_interface is complete, so
1816 * opt out if that is the case.
1817 */
1818 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1819 ret = -EBUSY;
1820 goto out;
1821 }
1822
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001823 switch (vif->type) {
1824 case NL80211_IFTYPE_STATION:
1825 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001826 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001827 break;
1828 case NL80211_IFTYPE_ADHOC:
1829 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001830 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001831 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001832 case NL80211_IFTYPE_AP:
1833 wl->bss_type = BSS_TYPE_AP_BSS;
1834 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001835 default:
1836 ret = -EOPNOTSUPP;
1837 goto out;
1838 }
1839
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001840 role_type = wl12xx_get_role_type(wl);
1841 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1842 ret = -EINVAL;
1843 goto out;
1844 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001845 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846
1847 if (wl->state != WL1271_STATE_OFF) {
1848 wl1271_error("cannot start because not in off state: %d",
1849 wl->state);
1850 ret = -EBUSY;
1851 goto out;
1852 }
1853
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001854 while (retries) {
1855 retries--;
1856 ret = wl1271_chip_wakeup(wl);
1857 if (ret < 0)
1858 goto power_off;
1859
1860 ret = wl1271_boot(wl);
1861 if (ret < 0)
1862 goto power_off;
1863
Eliad Peller227e81e2011-08-14 13:17:26 +03001864 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1865 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001866 /*
1867 * The device role is a special role used for
1868 * rx and tx frames prior to association (as
1869 * the STA role can get packets only from
1870 * its associated bssid)
1871 */
1872 ret = wl12xx_cmd_role_enable(wl,
1873 WL1271_ROLE_DEVICE,
1874 &wl->dev_role_id);
1875 if (ret < 0)
1876 goto irq_disable;
1877 }
1878
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001879 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1880 if (ret < 0)
1881 goto irq_disable;
1882
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001883 ret = wl1271_hw_init(wl);
1884 if (ret < 0)
1885 goto irq_disable;
1886
Eliad Peller71125ab2010-10-28 21:46:43 +02001887 booted = true;
1888 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001889
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001890irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001891 mutex_unlock(&wl->mutex);
1892 /* Unlocking the mutex in the middle of handling is
1893 inherently unsafe. In this case we deem it safe to do,
1894 because we need to let any possibly pending IRQ out of
1895 the system (and while we are WL1271_STATE_OFF the IRQ
1896 work function will not do anything.) Also, any other
1897 possible concurrent operations will fail due to the
1898 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001899 wl1271_disable_interrupts(wl);
1900 wl1271_flush_deferred_work(wl);
1901 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001902 mutex_lock(&wl->mutex);
1903power_off:
1904 wl1271_power_off(wl);
1905 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906
Eliad Peller71125ab2010-10-28 21:46:43 +02001907 if (!booted) {
1908 wl1271_error("firmware boot failed despite %d retries",
1909 WL1271_BOOT_RETRIES);
1910 goto out;
1911 }
1912
1913 wl->vif = vif;
1914 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001915 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001916 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001917
1918 /* update hw/fw version info in wiphy struct */
1919 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001920 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001921 sizeof(wiphy->fw_version));
1922
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001923 /*
1924 * Now we know if 11a is supported (info from the NVS), so disable
1925 * 11a channels if not supported
1926 */
1927 if (!wl->enable_11a)
1928 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1929
1930 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1931 wl->enable_11a ? "" : "not ");
1932
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001933out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 mutex_unlock(&wl->mutex);
1935
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001936 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001937 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001938 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001939 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 return ret;
1942}
1943
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001944static void __wl1271_op_remove_interface(struct wl1271 *wl,
1945 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001947 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001949 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001951 /* because of hardware recovery, we may get here twice */
1952 if (wl->state != WL1271_STATE_ON)
1953 return;
1954
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001955 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001957 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001958 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001959 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001960
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001961 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001962 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001963 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001964
Luciano Coelho08688d62010-07-08 17:50:07 +03001965 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001966 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001967 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001968 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001969 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 }
1971
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001972 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1973 /* disable active roles */
1974 ret = wl1271_ps_elp_wakeup(wl);
1975 if (ret < 0)
1976 goto deinit;
1977
Eliad Peller04e80792011-08-14 13:17:09 +03001978 if (wl->bss_type == BSS_TYPE_STA_BSS) {
1979 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
1980 if (ret < 0)
1981 goto deinit;
1982 }
1983
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001984 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
1985 if (ret < 0)
1986 goto deinit;
1987
1988 wl1271_ps_elp_sleep(wl);
1989 }
1990deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03001991 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001992 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03001993 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03001994 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
1995 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001996
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001997 /*
1998 * this must be before the cancel_work calls below, so that the work
1999 * functions don't perform further work.
2000 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001 wl->state = WL1271_STATE_OFF;
2002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 mutex_unlock(&wl->mutex);
2004
Ido Yariva6208652011-03-01 15:14:41 +02002005 wl1271_disable_interrupts(wl);
2006 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002007 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002008 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002010 del_timer_sync(&wl->rx_streaming_timer);
2011 cancel_work_sync(&wl->rx_streaming_enable_work);
2012 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002013 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002014 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015
2016 mutex_lock(&wl->mutex);
2017
2018 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002019 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020 wl1271_power_off(wl);
2021
2022 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002023 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002026 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002027 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028
2029 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002030 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2032 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002033 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034 wl->tx_results_count = 0;
2035 wl->tx_packets_count = 0;
2036 wl->time_offset = 0;
2037 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002038 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002039 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002040 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002041 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002042 wl->ap_fw_ps_map = 0;
2043 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002044 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002045 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002046 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002047 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2048 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002049 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002050
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002051 /* The system link is always allocated */
2052 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2053
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002054 /*
2055 * this is performed after the cancel_work calls and the associated
2056 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2057 * get executed before all these vars have been reset.
2058 */
2059 wl->flags = 0;
2060
Eliad Peller4d56ad92011-08-14 13:17:05 +03002061 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002063 wl->tx_allocated_pkts = 0;
2064 for (i = 0; i < NUM_TX_QUEUES; i++)
2065 wl->tx_pkts_freed[i] = 0;
2066
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002068
2069 kfree(wl->fw_status);
2070 wl->fw_status = NULL;
2071 kfree(wl->tx_res_if);
2072 wl->tx_res_if = NULL;
2073 kfree(wl->target_mem_map);
2074 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002075}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002076
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002077static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2078 struct ieee80211_vif *vif)
2079{
2080 struct wl1271 *wl = hw->priv;
2081
2082 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002083 /*
2084 * wl->vif can be null here if someone shuts down the interface
2085 * just when hardware recovery has been started.
2086 */
2087 if (wl->vif) {
2088 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002089 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002090 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002091
Juuso Oikarinen67353292010-11-18 15:19:02 +02002092 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002093 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094}
2095
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002096static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002097{
2098 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002099 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002100
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002101 /*
2102 * One of the side effects of the JOIN command is that is clears
2103 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2104 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002105 * Currently the only valid scenario for JOIN during association
2106 * is on roaming, in which case we will also be given new keys.
2107 * Keep the below message for now, unless it starts bothering
2108 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002109 */
2110 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2111 wl1271_info("JOIN while associated.");
2112
2113 if (set_assoc)
2114 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2115
Eliad Peller227e81e2011-08-14 13:17:26 +03002116 if (is_ibss)
2117 ret = wl12xx_cmd_role_start_ibss(wl);
2118 else
2119 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002120 if (ret < 0)
2121 goto out;
2122
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002123 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2124 goto out;
2125
2126 /*
2127 * The join command disable the keep-alive mode, shut down its process,
2128 * and also clear the template config, so we need to reset it all after
2129 * the join. The acx_aid starts the keep-alive process, and the order
2130 * of the commands below is relevant.
2131 */
2132 ret = wl1271_acx_keep_alive_mode(wl, true);
2133 if (ret < 0)
2134 goto out;
2135
2136 ret = wl1271_acx_aid(wl, wl->aid);
2137 if (ret < 0)
2138 goto out;
2139
2140 ret = wl1271_cmd_build_klv_null_data(wl);
2141 if (ret < 0)
2142 goto out;
2143
2144 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2145 ACX_KEEP_ALIVE_TPL_VALID);
2146 if (ret < 0)
2147 goto out;
2148
2149out:
2150 return ret;
2151}
2152
2153static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002154{
2155 int ret;
2156
2157 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002158 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002159 if (ret < 0)
2160 goto out;
2161
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002162 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002163
Oz Krakowskib992c682011-06-26 10:36:02 +03002164 /* reset TX security counters on a clean disconnect */
2165 wl->tx_security_last_seq_lsb = 0;
2166 wl->tx_security_seq = 0;
2167
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002168out:
2169 return ret;
2170}
2171
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002172static void wl1271_set_band_rate(struct wl1271 *wl)
2173{
2174 if (wl->band == IEEE80211_BAND_2GHZ)
2175 wl->basic_rate_set = wl->conf.tx.basic_rate;
2176 else
2177 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2178}
2179
Eliad Peller251c1772011-08-14 13:17:17 +03002180static bool wl12xx_is_roc(struct wl1271 *wl)
2181{
2182 u8 role_id;
2183
2184 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2185 if (role_id >= WL12XX_MAX_ROLES)
2186 return false;
2187
2188 return true;
2189}
2190
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002191static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002192{
2193 int ret;
2194
2195 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002196 /* no need to croc if we weren't busy (e.g. during boot) */
2197 if (wl12xx_is_roc(wl)) {
2198 ret = wl12xx_croc(wl, wl->dev_role_id);
2199 if (ret < 0)
2200 goto out;
2201
2202 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002203 if (ret < 0)
2204 goto out;
2205 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002206 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002207 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002208 if (ret < 0)
2209 goto out;
2210 ret = wl1271_acx_keep_alive_config(
2211 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2212 ACX_KEEP_ALIVE_TPL_INVALID);
2213 if (ret < 0)
2214 goto out;
2215 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2216 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002217 /* The current firmware only supports sched_scan in idle */
2218 if (wl->sched_scanning) {
2219 wl1271_scan_sched_scan_stop(wl);
2220 ieee80211_sched_scan_stopped(wl->hw);
2221 }
2222
Eliad Peller251c1772011-08-14 13:17:17 +03002223 ret = wl12xx_cmd_role_start_dev(wl);
2224 if (ret < 0)
2225 goto out;
2226
2227 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002228 if (ret < 0)
2229 goto out;
2230 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2231 }
2232
2233out:
2234 return ret;
2235}
2236
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002237static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2238{
2239 struct wl1271 *wl = hw->priv;
2240 struct ieee80211_conf *conf = &hw->conf;
2241 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002242 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002243
2244 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2245
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002246 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2247 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002248 channel,
2249 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002250 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002251 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2252 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002253
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002254 /*
2255 * mac80211 will go to idle nearly immediately after transmitting some
2256 * frames, such as the deauth. To make sure those frames reach the air,
2257 * wait here until the TX queue is fully flushed.
2258 */
2259 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2260 (conf->flags & IEEE80211_CONF_IDLE))
2261 wl1271_tx_flush(wl);
2262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002263 mutex_lock(&wl->mutex);
2264
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002265 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002266 /* we support configuring the channel and band while off */
2267 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2268 wl->band = conf->channel->band;
2269 wl->channel = channel;
2270 }
2271
Arik Nemtsov097f8822011-06-27 22:06:34 +03002272 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2273 wl->power_level = conf->power_level;
2274
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002275 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002276 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002277
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002278 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2279
Ido Yariva6208652011-03-01 15:14:41 +02002280 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281 if (ret < 0)
2282 goto out;
2283
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002284 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002285 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2286 ((wl->band != conf->channel->band) ||
2287 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002288 wl->band = conf->channel->band;
2289 wl->channel = channel;
2290
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002291 if (!is_ap) {
2292 /*
2293 * FIXME: the mac80211 should really provide a fixed
2294 * rate to use here. for now, just use the smallest
2295 * possible rate for the band as a fixed rate for
2296 * association frames and other control messages.
2297 */
2298 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2299 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002300
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002301 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2302 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002303 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002304 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002305 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002306
Eliad Peller251c1772011-08-14 13:17:17 +03002307 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2308 if (wl12xx_is_roc(wl)) {
2309 /* roaming */
2310 ret = wl12xx_croc(wl, wl->dev_role_id);
2311 if (ret < 0)
2312 goto out_sleep;
2313 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002314 ret = wl1271_join(wl, false);
2315 if (ret < 0)
2316 wl1271_warning("cmd join on channel "
2317 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002318 } else {
2319 /*
2320 * change the ROC channel. do it only if we are
2321 * not idle. otherwise, CROC will be called
2322 * anyway.
2323 */
2324 if (wl12xx_is_roc(wl) &&
2325 !(conf->flags & IEEE80211_CONF_IDLE)) {
2326 ret = wl12xx_croc(wl, wl->dev_role_id);
2327 if (ret < 0)
2328 goto out_sleep;
2329
2330 ret = wl12xx_roc(wl, wl->dev_role_id);
2331 if (ret < 0)
2332 wl1271_warning("roc failed %d",
2333 ret);
2334 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002335 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002336 }
2337 }
2338
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002339 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2340 ret = wl1271_sta_handle_idle(wl,
2341 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002342 if (ret < 0)
2343 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002344 }
2345
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002346 /*
2347 * if mac80211 changes the PSM mode, make sure the mode is not
2348 * incorrectly changed after the pspoll failure active window.
2349 */
2350 if (changed & IEEE80211_CONF_CHANGE_PS)
2351 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2352
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002353 if (conf->flags & IEEE80211_CONF_PS &&
2354 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2355 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356
2357 /*
2358 * We enter PSM only if we're already associated.
2359 * If we're not, we'll enter it when joining an SSID,
2360 * through the bss_info_changed() hook.
2361 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002362 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002363 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002364 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002365 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002366 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002368 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002369 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002371 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002373 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002374 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002375 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 }
2377
2378 if (conf->power_level != wl->power_level) {
2379 ret = wl1271_acx_tx_power(wl, conf->power_level);
2380 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002381 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382
2383 wl->power_level = conf->power_level;
2384 }
2385
2386out_sleep:
2387 wl1271_ps_elp_sleep(wl);
2388
2389out:
2390 mutex_unlock(&wl->mutex);
2391
2392 return ret;
2393}
2394
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002395struct wl1271_filter_params {
2396 bool enabled;
2397 int mc_list_length;
2398 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2399};
2400
Jiri Pirko22bedad2010-04-01 21:22:57 +00002401static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2402 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002403{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002404 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002405 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002406 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002407
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002408 if (unlikely(wl->state == WL1271_STATE_OFF))
2409 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002410
Juuso Oikarinen74441132009-10-13 12:47:53 +03002411 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002412 if (!fp) {
2413 wl1271_error("Out of memory setting filters.");
2414 return 0;
2415 }
2416
2417 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002418 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002419 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2420 fp->enabled = false;
2421 } else {
2422 fp->enabled = true;
2423 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002424 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002425 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002426 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002427 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002428 }
2429
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002430 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002431}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002432
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002433#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2434 FIF_ALLMULTI | \
2435 FIF_FCSFAIL | \
2436 FIF_BCN_PRBRESP_PROMISC | \
2437 FIF_CONTROL | \
2438 FIF_OTHER_BSS)
2439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2441 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002442 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002444 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002446 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447
Arik Nemtsov7d057862010-10-16 19:25:35 +02002448 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2449 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002451 mutex_lock(&wl->mutex);
2452
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002453 *total &= WL1271_SUPPORTED_FILTERS;
2454 changed &= WL1271_SUPPORTED_FILTERS;
2455
2456 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002457 goto out;
2458
Ido Yariva6208652011-03-01 15:14:41 +02002459 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002460 if (ret < 0)
2461 goto out;
2462
Arik Nemtsov7d057862010-10-16 19:25:35 +02002463 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2464 if (*total & FIF_ALLMULTI)
2465 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2466 else if (fp)
2467 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2468 fp->mc_list,
2469 fp->mc_list_length);
2470 if (ret < 0)
2471 goto out_sleep;
2472 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002474 /*
2475 * the fw doesn't provide an api to configure the filters. instead,
2476 * the filters configuration is based on the active roles / ROC
2477 * state.
2478 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002479
2480out_sleep:
2481 wl1271_ps_elp_sleep(wl);
2482
2483out:
2484 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002485 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002486}
2487
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002488static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2489 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2490 u16 tx_seq_16)
2491{
2492 struct wl1271_ap_key *ap_key;
2493 int i;
2494
2495 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2496
2497 if (key_size > MAX_KEY_SIZE)
2498 return -EINVAL;
2499
2500 /*
2501 * Find next free entry in ap_keys. Also check we are not replacing
2502 * an existing key.
2503 */
2504 for (i = 0; i < MAX_NUM_KEYS; i++) {
2505 if (wl->recorded_ap_keys[i] == NULL)
2506 break;
2507
2508 if (wl->recorded_ap_keys[i]->id == id) {
2509 wl1271_warning("trying to record key replacement");
2510 return -EINVAL;
2511 }
2512 }
2513
2514 if (i == MAX_NUM_KEYS)
2515 return -EBUSY;
2516
2517 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2518 if (!ap_key)
2519 return -ENOMEM;
2520
2521 ap_key->id = id;
2522 ap_key->key_type = key_type;
2523 ap_key->key_size = key_size;
2524 memcpy(ap_key->key, key, key_size);
2525 ap_key->hlid = hlid;
2526 ap_key->tx_seq_32 = tx_seq_32;
2527 ap_key->tx_seq_16 = tx_seq_16;
2528
2529 wl->recorded_ap_keys[i] = ap_key;
2530 return 0;
2531}
2532
2533static void wl1271_free_ap_keys(struct wl1271 *wl)
2534{
2535 int i;
2536
2537 for (i = 0; i < MAX_NUM_KEYS; i++) {
2538 kfree(wl->recorded_ap_keys[i]);
2539 wl->recorded_ap_keys[i] = NULL;
2540 }
2541}
2542
2543static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2544{
2545 int i, ret = 0;
2546 struct wl1271_ap_key *key;
2547 bool wep_key_added = false;
2548
2549 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002550 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002551 if (wl->recorded_ap_keys[i] == NULL)
2552 break;
2553
2554 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002555 hlid = key->hlid;
2556 if (hlid == WL12XX_INVALID_LINK_ID)
2557 hlid = wl->ap_bcast_hlid;
2558
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002559 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2560 key->id, key->key_type,
2561 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002562 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002563 key->tx_seq_16);
2564 if (ret < 0)
2565 goto out;
2566
2567 if (key->key_type == KEY_WEP)
2568 wep_key_added = true;
2569 }
2570
2571 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002572 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002573 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002574 if (ret < 0)
2575 goto out;
2576 }
2577
2578out:
2579 wl1271_free_ap_keys(wl);
2580 return ret;
2581}
2582
2583static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2584 u8 key_size, const u8 *key, u32 tx_seq_32,
2585 u16 tx_seq_16, struct ieee80211_sta *sta)
2586{
2587 int ret;
2588 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2589
2590 if (is_ap) {
2591 struct wl1271_station *wl_sta;
2592 u8 hlid;
2593
2594 if (sta) {
2595 wl_sta = (struct wl1271_station *)sta->drv_priv;
2596 hlid = wl_sta->hlid;
2597 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002598 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002599 }
2600
2601 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2602 /*
2603 * We do not support removing keys after AP shutdown.
2604 * Pretend we do to make mac80211 happy.
2605 */
2606 if (action != KEY_ADD_OR_REPLACE)
2607 return 0;
2608
2609 ret = wl1271_record_ap_key(wl, id,
2610 key_type, key_size,
2611 key, hlid, tx_seq_32,
2612 tx_seq_16);
2613 } else {
2614 ret = wl1271_cmd_set_ap_key(wl, action,
2615 id, key_type, key_size,
2616 key, hlid, tx_seq_32,
2617 tx_seq_16);
2618 }
2619
2620 if (ret < 0)
2621 return ret;
2622 } else {
2623 const u8 *addr;
2624 static const u8 bcast_addr[ETH_ALEN] = {
2625 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2626 };
2627
2628 addr = sta ? sta->addr : bcast_addr;
2629
2630 if (is_zero_ether_addr(addr)) {
2631 /* We dont support TX only encryption */
2632 return -EOPNOTSUPP;
2633 }
2634
2635 /* The wl1271 does not allow to remove unicast keys - they
2636 will be cleared automatically on next CMD_JOIN. Ignore the
2637 request silently, as we dont want the mac80211 to emit
2638 an error message. */
2639 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2640 return 0;
2641
Eliad Peller010d3d32011-08-14 13:17:31 +03002642 /* don't remove key if hlid was already deleted */
2643 if (action == KEY_REMOVE &&
2644 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2645 return 0;
2646
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002647 ret = wl1271_cmd_set_sta_key(wl, action,
2648 id, key_type, key_size,
2649 key, addr, tx_seq_32,
2650 tx_seq_16);
2651 if (ret < 0)
2652 return ret;
2653
2654 /* the default WEP key needs to be configured at least once */
2655 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002656 ret = wl12xx_cmd_set_default_wep_key(wl,
2657 wl->default_key,
2658 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002659 if (ret < 0)
2660 return ret;
2661 }
2662 }
2663
2664 return 0;
2665}
2666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2668 struct ieee80211_vif *vif,
2669 struct ieee80211_sta *sta,
2670 struct ieee80211_key_conf *key_conf)
2671{
2672 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002673 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002674 u32 tx_seq_32 = 0;
2675 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002676 u8 key_type;
2677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2679
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002680 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002682 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002683 key_conf->keylen, key_conf->flags);
2684 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 mutex_lock(&wl->mutex);
2687
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002688 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2689 ret = -EAGAIN;
2690 goto out_unlock;
2691 }
2692
Ido Yariva6208652011-03-01 15:14:41 +02002693 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 if (ret < 0)
2695 goto out_unlock;
2696
Johannes Berg97359d12010-08-10 09:46:38 +02002697 switch (key_conf->cipher) {
2698 case WLAN_CIPHER_SUITE_WEP40:
2699 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002700 key_type = KEY_WEP;
2701
2702 key_conf->hw_key_idx = key_conf->keyidx;
2703 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002704 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705 key_type = KEY_TKIP;
2706
2707 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002708 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2709 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002710 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002711 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712 key_type = KEY_AES;
2713
2714 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002715 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2716 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002718 case WL1271_CIPHER_SUITE_GEM:
2719 key_type = KEY_GEM;
2720 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2721 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2722 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002723 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002724 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725
2726 ret = -EOPNOTSUPP;
2727 goto out_sleep;
2728 }
2729
2730 switch (cmd) {
2731 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002732 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2733 key_conf->keyidx, key_type,
2734 key_conf->keylen, key_conf->key,
2735 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736 if (ret < 0) {
2737 wl1271_error("Could not add or replace key");
2738 goto out_sleep;
2739 }
2740 break;
2741
2742 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002743 ret = wl1271_set_key(wl, KEY_REMOVE,
2744 key_conf->keyidx, key_type,
2745 key_conf->keylen, key_conf->key,
2746 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747 if (ret < 0) {
2748 wl1271_error("Could not remove key");
2749 goto out_sleep;
2750 }
2751 break;
2752
2753 default:
2754 wl1271_error("Unsupported key cmd 0x%x", cmd);
2755 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002756 break;
2757 }
2758
2759out_sleep:
2760 wl1271_ps_elp_sleep(wl);
2761
2762out_unlock:
2763 mutex_unlock(&wl->mutex);
2764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002765 return ret;
2766}
2767
2768static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002769 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002770 struct cfg80211_scan_request *req)
2771{
2772 struct wl1271 *wl = hw->priv;
2773 int ret;
2774 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002775 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002776
2777 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2778
2779 if (req->n_ssids) {
2780 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002781 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782 }
2783
2784 mutex_lock(&wl->mutex);
2785
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002786 if (wl->state == WL1271_STATE_OFF) {
2787 /*
2788 * We cannot return -EBUSY here because cfg80211 will expect
2789 * a call to ieee80211_scan_completed if we do - in this case
2790 * there won't be any call.
2791 */
2792 ret = -EAGAIN;
2793 goto out;
2794 }
2795
Ido Yariva6208652011-03-01 15:14:41 +02002796 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797 if (ret < 0)
2798 goto out;
2799
Eliad Peller251c1772011-08-14 13:17:17 +03002800 /* cancel ROC before scanning */
2801 if (wl12xx_is_roc(wl)) {
2802 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2803 /* don't allow scanning right now */
2804 ret = -EBUSY;
2805 goto out_sleep;
2806 }
2807 wl12xx_croc(wl, wl->dev_role_id);
2808 wl12xx_cmd_role_stop_dev(wl);
2809 }
2810
Luciano Coelho5924f892010-08-04 03:46:22 +03002811 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002812out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002813 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002814out:
2815 mutex_unlock(&wl->mutex);
2816
2817 return ret;
2818}
2819
Eliad Peller73ecce32011-06-27 13:06:45 +03002820static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2821 struct ieee80211_vif *vif)
2822{
2823 struct wl1271 *wl = hw->priv;
2824 int ret;
2825
2826 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2827
2828 mutex_lock(&wl->mutex);
2829
2830 if (wl->state == WL1271_STATE_OFF)
2831 goto out;
2832
2833 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2834 goto out;
2835
2836 ret = wl1271_ps_elp_wakeup(wl);
2837 if (ret < 0)
2838 goto out;
2839
2840 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2841 ret = wl1271_scan_stop(wl);
2842 if (ret < 0)
2843 goto out_sleep;
2844 }
2845 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2846 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2847 wl->scan.req = NULL;
2848 ieee80211_scan_completed(wl->hw, true);
2849
2850out_sleep:
2851 wl1271_ps_elp_sleep(wl);
2852out:
2853 mutex_unlock(&wl->mutex);
2854
2855 cancel_delayed_work_sync(&wl->scan_complete_work);
2856}
2857
Luciano Coelho33c2c062011-05-10 14:46:02 +03002858static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2859 struct ieee80211_vif *vif,
2860 struct cfg80211_sched_scan_request *req,
2861 struct ieee80211_sched_scan_ies *ies)
2862{
2863 struct wl1271 *wl = hw->priv;
2864 int ret;
2865
2866 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2867
2868 mutex_lock(&wl->mutex);
2869
2870 ret = wl1271_ps_elp_wakeup(wl);
2871 if (ret < 0)
2872 goto out;
2873
2874 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2875 if (ret < 0)
2876 goto out_sleep;
2877
2878 ret = wl1271_scan_sched_scan_start(wl);
2879 if (ret < 0)
2880 goto out_sleep;
2881
2882 wl->sched_scanning = true;
2883
2884out_sleep:
2885 wl1271_ps_elp_sleep(wl);
2886out:
2887 mutex_unlock(&wl->mutex);
2888 return ret;
2889}
2890
2891static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2892 struct ieee80211_vif *vif)
2893{
2894 struct wl1271 *wl = hw->priv;
2895 int ret;
2896
2897 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2898
2899 mutex_lock(&wl->mutex);
2900
2901 ret = wl1271_ps_elp_wakeup(wl);
2902 if (ret < 0)
2903 goto out;
2904
2905 wl1271_scan_sched_scan_stop(wl);
2906
2907 wl1271_ps_elp_sleep(wl);
2908out:
2909 mutex_unlock(&wl->mutex);
2910}
2911
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002912static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2913{
2914 struct wl1271 *wl = hw->priv;
2915 int ret = 0;
2916
2917 mutex_lock(&wl->mutex);
2918
2919 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2920 ret = -EAGAIN;
2921 goto out;
2922 }
2923
Ido Yariva6208652011-03-01 15:14:41 +02002924 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002925 if (ret < 0)
2926 goto out;
2927
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002928 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002929 if (ret < 0)
2930 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2931
2932 wl1271_ps_elp_sleep(wl);
2933
2934out:
2935 mutex_unlock(&wl->mutex);
2936
2937 return ret;
2938}
2939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002940static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2941{
2942 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002943 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944
2945 mutex_lock(&wl->mutex);
2946
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002947 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2948 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002949 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002950 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002951
Ido Yariva6208652011-03-01 15:14:41 +02002952 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 if (ret < 0)
2954 goto out;
2955
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002956 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 if (ret < 0)
2958 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2959
2960 wl1271_ps_elp_sleep(wl);
2961
2962out:
2963 mutex_unlock(&wl->mutex);
2964
2965 return ret;
2966}
2967
Arik Nemtsove78a2872010-10-16 19:07:21 +02002968static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002969 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002970{
Eliad Peller889cb362011-05-01 09:56:45 +03002971 u8 ssid_len;
2972 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2973 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002974
Eliad Peller889cb362011-05-01 09:56:45 +03002975 if (!ptr) {
2976 wl1271_error("No SSID in IEs!");
2977 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002978 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002979
Eliad Peller889cb362011-05-01 09:56:45 +03002980 ssid_len = ptr[1];
2981 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2982 wl1271_error("SSID is too long!");
2983 return -EINVAL;
2984 }
2985
2986 wl->ssid_len = ssid_len;
2987 memcpy(wl->ssid, ptr+2, ssid_len);
2988 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002989}
2990
Arik Nemtsove78a2872010-10-16 19:07:21 +02002991static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2992 struct ieee80211_bss_conf *bss_conf,
2993 u32 changed)
2994{
2995 int ret = 0;
2996
2997 if (changed & BSS_CHANGED_ERP_SLOT) {
2998 if (bss_conf->use_short_slot)
2999 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3000 else
3001 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3002 if (ret < 0) {
3003 wl1271_warning("Set slot time failed %d", ret);
3004 goto out;
3005 }
3006 }
3007
3008 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3009 if (bss_conf->use_short_preamble)
3010 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3011 else
3012 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3013 }
3014
3015 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3016 if (bss_conf->use_cts_prot)
3017 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3018 else
3019 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3020 if (ret < 0) {
3021 wl1271_warning("Set ctsprotect failed %d", ret);
3022 goto out;
3023 }
3024 }
3025
3026out:
3027 return ret;
3028}
3029
3030static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3031 struct ieee80211_vif *vif,
3032 struct ieee80211_bss_conf *bss_conf,
3033 u32 changed)
3034{
3035 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3036 int ret = 0;
3037
3038 if ((changed & BSS_CHANGED_BEACON_INT)) {
3039 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3040 bss_conf->beacon_int);
3041
3042 wl->beacon_int = bss_conf->beacon_int;
3043 }
3044
3045 if ((changed & BSS_CHANGED_BEACON)) {
3046 struct ieee80211_hdr *hdr;
3047 int ieoffset = offsetof(struct ieee80211_mgmt,
3048 u.beacon.variable);
3049 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3050 u16 tmpl_id;
3051
3052 if (!beacon)
3053 goto out;
3054
3055 wl1271_debug(DEBUG_MASTER, "beacon updated");
3056
3057 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3058 if (ret < 0) {
3059 dev_kfree_skb(beacon);
3060 goto out;
3061 }
3062 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3063 CMD_TEMPL_BEACON;
3064 ret = wl1271_cmd_template_set(wl, tmpl_id,
3065 beacon->data,
3066 beacon->len, 0,
3067 wl1271_tx_min_rate_get(wl));
3068 if (ret < 0) {
3069 dev_kfree_skb(beacon);
3070 goto out;
3071 }
3072
3073 hdr = (struct ieee80211_hdr *) beacon->data;
3074 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3075 IEEE80211_STYPE_PROBE_RESP);
3076
3077 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3078 CMD_TEMPL_PROBE_RESPONSE;
3079 ret = wl1271_cmd_template_set(wl,
3080 tmpl_id,
3081 beacon->data,
3082 beacon->len, 0,
3083 wl1271_tx_min_rate_get(wl));
3084 dev_kfree_skb(beacon);
3085 if (ret < 0)
3086 goto out;
3087 }
3088
3089out:
3090 return ret;
3091}
3092
3093/* AP mode changes */
3094static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003095 struct ieee80211_vif *vif,
3096 struct ieee80211_bss_conf *bss_conf,
3097 u32 changed)
3098{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003099 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003100
Arik Nemtsove78a2872010-10-16 19:07:21 +02003101 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3102 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003103
Arik Nemtsove78a2872010-10-16 19:07:21 +02003104 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3105 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003106
Arik Nemtsov70f47422011-04-18 14:15:25 +03003107 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003108 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003109 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003110 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003111 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003112
3113 ret = wl1271_ap_init_templates(wl);
3114 if (ret < 0)
3115 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003116 }
3117
Arik Nemtsove78a2872010-10-16 19:07:21 +02003118 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3119 if (ret < 0)
3120 goto out;
3121
3122 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3123 if (bss_conf->enable_beacon) {
3124 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003125 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003126 if (ret < 0)
3127 goto out;
3128
3129 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3130 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003131
3132 ret = wl1271_ap_init_hwenc(wl);
3133 if (ret < 0)
3134 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003135 }
3136 } else {
3137 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003138 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003139 if (ret < 0)
3140 goto out;
3141
3142 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3143 wl1271_debug(DEBUG_AP, "stopped AP");
3144 }
3145 }
3146 }
3147
3148 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3149 if (ret < 0)
3150 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003151
3152 /* Handle HT information change */
3153 if ((changed & BSS_CHANGED_HT) &&
3154 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3155 ret = wl1271_acx_set_ht_information(wl,
3156 bss_conf->ht_operation_mode);
3157 if (ret < 0) {
3158 wl1271_warning("Set ht information failed %d", ret);
3159 goto out;
3160 }
3161 }
3162
Arik Nemtsove78a2872010-10-16 19:07:21 +02003163out:
3164 return;
3165}
3166
3167/* STA/IBSS mode changes */
3168static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3169 struct ieee80211_vif *vif,
3170 struct ieee80211_bss_conf *bss_conf,
3171 u32 changed)
3172{
3173 bool do_join = false, set_assoc = false;
3174 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003175 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003176 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003177 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003178 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003179 bool sta_exists = false;
3180 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003181
3182 if (is_ibss) {
3183 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3184 changed);
3185 if (ret < 0)
3186 goto out;
3187 }
3188
Eliad Peller227e81e2011-08-14 13:17:26 +03003189 if (changed & BSS_CHANGED_IBSS) {
3190 if (bss_conf->ibss_joined) {
3191 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3192 ibss_joined = true;
3193 } else {
3194 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3195 &wl->flags)) {
3196 wl1271_unjoin(wl);
3197 wl12xx_cmd_role_start_dev(wl);
3198 wl12xx_roc(wl, wl->dev_role_id);
3199 }
3200 }
3201 }
3202
3203 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003204 do_join = true;
3205
3206 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003207 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003208 do_join = true;
3209
Eliad Peller227e81e2011-08-14 13:17:26 +03003210 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003211 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3212 bss_conf->enable_beacon ? "enabled" : "disabled");
3213
3214 if (bss_conf->enable_beacon)
3215 wl->set_bss_type = BSS_TYPE_IBSS;
3216 else
3217 wl->set_bss_type = BSS_TYPE_STA_BSS;
3218 do_join = true;
3219 }
3220
Arik Nemtsove78a2872010-10-16 19:07:21 +02003221 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003222 bool enable = false;
3223 if (bss_conf->cqm_rssi_thold)
3224 enable = true;
3225 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3226 bss_conf->cqm_rssi_thold,
3227 bss_conf->cqm_rssi_hyst);
3228 if (ret < 0)
3229 goto out;
3230 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3231 }
3232
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003233 if ((changed & BSS_CHANGED_BSSID) &&
3234 /*
3235 * Now we know the correct bssid, so we send a new join command
3236 * and enable the BSSID filter
3237 */
3238 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003239 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003240
Eliad Pellerfa287b82010-12-26 09:27:50 +01003241 if (!is_zero_ether_addr(wl->bssid)) {
3242 ret = wl1271_cmd_build_null_data(wl);
3243 if (ret < 0)
3244 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003245
Eliad Pellerfa287b82010-12-26 09:27:50 +01003246 ret = wl1271_build_qos_null_data(wl);
3247 if (ret < 0)
3248 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003249
Eliad Pellerfa287b82010-12-26 09:27:50 +01003250 /* Need to update the BSSID (for filtering etc) */
3251 do_join = true;
3252 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003253 }
3254
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003255 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3256 rcu_read_lock();
3257 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3258 if (!sta)
3259 goto sta_not_found;
3260
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003261 /* save the supp_rates of the ap */
3262 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3263 if (sta->ht_cap.ht_supported)
3264 sta_rate_set |=
3265 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003266 sta_ht_cap = sta->ht_cap;
3267 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003268
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003269sta_not_found:
3270 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003271 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003272
Arik Nemtsove78a2872010-10-16 19:07:21 +02003273 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003274 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003275 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003276 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003277 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003278 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003279
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003280 wl->ps_poll_failures = 0;
3281
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003282 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003283 * use basic rates from AP, and determine lowest rate
3284 * to use with control frames.
3285 */
3286 rates = bss_conf->basic_rates;
3287 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3288 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003289 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003290 if (sta_rate_set)
3291 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3292 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003293 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003294 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003295 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003296
3297 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003298 * with wl1271, we don't need to update the
3299 * beacon_int and dtim_period, because the firmware
3300 * updates it by itself when the first beacon is
3301 * received after a join.
3302 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003303 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3304 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003305 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003307 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003308 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003309 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003310 dev_kfree_skb(wl->probereq);
3311 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3312 ieoffset = offsetof(struct ieee80211_mgmt,
3313 u.probe_req.variable);
3314 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003315
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003316 /* enable the connection monitoring feature */
3317 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003318 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003319 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003320
3321 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003322 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3323 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003324 enum wl1271_cmd_ps_mode mode;
3325
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003326 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003327 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003328 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003329 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003330 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003331 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003332 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003333 } else {
3334 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003335 bool was_assoc =
3336 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3337 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003338 bool was_ifup =
3339 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3340 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003341 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003342
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003343 /* free probe-request template */
3344 dev_kfree_skb(wl->probereq);
3345 wl->probereq = NULL;
3346
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003347 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003348 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003349
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003350 /* revert back to minimum rates for the current band */
3351 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003352 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003353 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003354 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003356
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003357 /* disable connection monitor features */
3358 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003359
3360 /* Disable the keep-alive feature */
3361 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003362 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003364
3365 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003366 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003367 u32 conf_flags = wl->hw->conf.flags;
3368 /*
3369 * we might have to disable roc, if there was
3370 * no IF_OPER_UP notification.
3371 */
3372 if (!was_ifup) {
3373 ret = wl12xx_croc(wl, wl->role_id);
3374 if (ret < 0)
3375 goto out;
3376 }
3377 /*
3378 * (we also need to disable roc in case of
3379 * roaming on the same channel. until we will
3380 * have a better flow...)
3381 */
3382 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3383 ret = wl12xx_croc(wl, wl->dev_role_id);
3384 if (ret < 0)
3385 goto out;
3386 }
3387
Eliad Peller30df14d2011-04-05 19:13:28 +03003388 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003389 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3390 wl12xx_cmd_role_start_dev(wl);
3391 wl12xx_roc(wl, wl->dev_role_id);
3392 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003393 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003394 }
3395 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003396
Eliad Pellerd192d262011-05-24 14:33:08 +03003397 if (changed & BSS_CHANGED_IBSS) {
3398 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3399 bss_conf->ibss_joined);
3400
3401 if (bss_conf->ibss_joined) {
3402 u32 rates = bss_conf->basic_rates;
3403 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3404 rates);
3405 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3406
3407 /* by default, use 11b rates */
3408 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3409 ret = wl1271_acx_sta_rate_policies(wl);
3410 if (ret < 0)
3411 goto out;
3412 }
3413 }
3414
Arik Nemtsove78a2872010-10-16 19:07:21 +02003415 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3416 if (ret < 0)
3417 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003418
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003419 if (changed & BSS_CHANGED_ARP_FILTER) {
3420 __be32 addr = bss_conf->arp_addr_list[0];
3421 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3422
Eliad Pellerc5312772010-12-09 11:31:27 +02003423 if (bss_conf->arp_addr_cnt == 1 &&
3424 bss_conf->arp_filter_enabled) {
3425 /*
3426 * The template should have been configured only upon
3427 * association. however, it seems that the correct ip
3428 * isn't being set (when sending), so we have to
3429 * reconfigure the template upon every ip change.
3430 */
3431 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3432 if (ret < 0) {
3433 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003434 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003435 }
3436
3437 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003438 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003439 addr);
3440 } else
3441 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003442
3443 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003444 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003445 }
3446
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003447 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003448 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003449 if (ret < 0) {
3450 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003452 }
Eliad Peller251c1772011-08-14 13:17:17 +03003453
3454 /* ROC until connected (after EAPOL exchange) */
3455 if (!is_ibss) {
3456 ret = wl12xx_roc(wl, wl->role_id);
3457 if (ret < 0)
3458 goto out;
3459
3460 wl1271_check_operstate(wl,
3461 ieee80211_get_operstate(vif));
3462 }
3463 /*
3464 * stop device role if started (we might already be in
3465 * STA role). TODO: make it better.
3466 */
3467 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3468 ret = wl12xx_croc(wl, wl->dev_role_id);
3469 if (ret < 0)
3470 goto out;
3471
3472 ret = wl12xx_cmd_role_stop_dev(wl);
3473 if (ret < 0)
3474 goto out;
3475 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003476 }
3477
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003478 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003479 if (sta_exists) {
3480 if ((changed & BSS_CHANGED_HT) &&
3481 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003482 ret = wl1271_acx_set_ht_capabilities(wl,
3483 &sta_ht_cap,
3484 true,
3485 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003486 if (ret < 0) {
3487 wl1271_warning("Set ht cap true failed %d",
3488 ret);
3489 goto out;
3490 }
3491 }
3492 /* handle new association without HT and disassociation */
3493 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003494 ret = wl1271_acx_set_ht_capabilities(wl,
3495 &sta_ht_cap,
3496 false,
3497 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003498 if (ret < 0) {
3499 wl1271_warning("Set ht cap false failed %d",
3500 ret);
3501 goto out;
3502 }
3503 }
3504 }
3505
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003506 /* Handle HT information change. Done after join. */
3507 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003508 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3509 ret = wl1271_acx_set_ht_information(wl,
3510 bss_conf->ht_operation_mode);
3511 if (ret < 0) {
3512 wl1271_warning("Set ht information failed %d", ret);
3513 goto out;
3514 }
3515 }
3516
Arik Nemtsove78a2872010-10-16 19:07:21 +02003517out:
3518 return;
3519}
3520
3521static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3522 struct ieee80211_vif *vif,
3523 struct ieee80211_bss_conf *bss_conf,
3524 u32 changed)
3525{
3526 struct wl1271 *wl = hw->priv;
3527 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3528 int ret;
3529
3530 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3531 (int)changed);
3532
3533 mutex_lock(&wl->mutex);
3534
3535 if (unlikely(wl->state == WL1271_STATE_OFF))
3536 goto out;
3537
Ido Yariva6208652011-03-01 15:14:41 +02003538 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 if (ret < 0)
3540 goto out;
3541
3542 if (is_ap)
3543 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3544 else
3545 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3546
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003547 wl1271_ps_elp_sleep(wl);
3548
3549out:
3550 mutex_unlock(&wl->mutex);
3551}
3552
Kalle Valoc6999d82010-02-18 13:25:41 +02003553static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3554 const struct ieee80211_tx_queue_params *params)
3555{
3556 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003557 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003558 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003559
3560 mutex_lock(&wl->mutex);
3561
3562 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3563
Kalle Valo4695dc92010-03-18 12:26:38 +02003564 if (params->uapsd)
3565 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3566 else
3567 ps_scheme = CONF_PS_SCHEME_LEGACY;
3568
Arik Nemtsov488fc542010-10-16 20:33:45 +02003569 if (wl->state == WL1271_STATE_OFF) {
3570 /*
3571 * If the state is off, the parameters will be recorded and
3572 * configured on init. This happens in AP-mode.
3573 */
3574 struct conf_tx_ac_category *conf_ac =
3575 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3576 struct conf_tx_tid *conf_tid =
3577 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3578
3579 conf_ac->ac = wl1271_tx_get_queue(queue);
3580 conf_ac->cw_min = (u8)params->cw_min;
3581 conf_ac->cw_max = params->cw_max;
3582 conf_ac->aifsn = params->aifs;
3583 conf_ac->tx_op_limit = params->txop << 5;
3584
3585 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3586 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3587 conf_tid->tsid = wl1271_tx_get_queue(queue);
3588 conf_tid->ps_scheme = ps_scheme;
3589 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3590 conf_tid->apsd_conf[0] = 0;
3591 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003592 goto out;
3593 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003594
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003595 ret = wl1271_ps_elp_wakeup(wl);
3596 if (ret < 0)
3597 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003598
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003599 /*
3600 * the txop is confed in units of 32us by the mac80211,
3601 * we need us
3602 */
3603 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3604 params->cw_min, params->cw_max,
3605 params->aifs, params->txop << 5);
3606 if (ret < 0)
3607 goto out_sleep;
3608
3609 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3610 CONF_CHANNEL_TYPE_EDCF,
3611 wl1271_tx_get_queue(queue),
3612 ps_scheme, CONF_ACK_POLICY_LEGACY,
3613 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003614
3615out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003616 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003617
3618out:
3619 mutex_unlock(&wl->mutex);
3620
3621 return ret;
3622}
3623
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003624static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3625{
3626
3627 struct wl1271 *wl = hw->priv;
3628 u64 mactime = ULLONG_MAX;
3629 int ret;
3630
3631 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3632
3633 mutex_lock(&wl->mutex);
3634
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003635 if (unlikely(wl->state == WL1271_STATE_OFF))
3636 goto out;
3637
Ido Yariva6208652011-03-01 15:14:41 +02003638 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003639 if (ret < 0)
3640 goto out;
3641
3642 ret = wl1271_acx_tsf_info(wl, &mactime);
3643 if (ret < 0)
3644 goto out_sleep;
3645
3646out_sleep:
3647 wl1271_ps_elp_sleep(wl);
3648
3649out:
3650 mutex_unlock(&wl->mutex);
3651 return mactime;
3652}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653
John W. Linvilleece550d2010-07-28 16:41:06 -04003654static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3655 struct survey_info *survey)
3656{
3657 struct wl1271 *wl = hw->priv;
3658 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003659
John W. Linvilleece550d2010-07-28 16:41:06 -04003660 if (idx != 0)
3661 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003662
John W. Linvilleece550d2010-07-28 16:41:06 -04003663 survey->channel = conf->channel;
3664 survey->filled = SURVEY_INFO_NOISE_DBM;
3665 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003666
John W. Linvilleece550d2010-07-28 16:41:06 -04003667 return 0;
3668}
3669
Arik Nemtsov409622e2011-02-23 00:22:29 +02003670static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003671 struct ieee80211_sta *sta,
3672 u8 *hlid)
3673{
3674 struct wl1271_station *wl_sta;
3675 int id;
3676
3677 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3678 if (id >= AP_MAX_STATIONS) {
3679 wl1271_warning("could not allocate HLID - too much stations");
3680 return -EBUSY;
3681 }
3682
3683 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003684 __set_bit(id, wl->ap_hlid_map);
3685 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3686 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003687 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003688 return 0;
3689}
3690
Arik Nemtsov409622e2011-02-23 00:22:29 +02003691static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003692{
3693 int id = hlid - WL1271_AP_STA_HLID_START;
3694
Arik Nemtsov409622e2011-02-23 00:22:29 +02003695 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3696 return;
3697
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003698 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003699 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003700 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003701 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003702 __clear_bit(hlid, &wl->ap_ps_map);
3703 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003704}
3705
Arik Nemtsov3618f302011-06-26 10:36:03 +03003706bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3707{
3708 int id = hlid - WL1271_AP_STA_HLID_START;
3709 return test_bit(id, wl->ap_hlid_map);
3710}
3711
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003712static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3713 struct ieee80211_vif *vif,
3714 struct ieee80211_sta *sta)
3715{
3716 struct wl1271 *wl = hw->priv;
3717 int ret = 0;
3718 u8 hlid;
3719
3720 mutex_lock(&wl->mutex);
3721
3722 if (unlikely(wl->state == WL1271_STATE_OFF))
3723 goto out;
3724
3725 if (wl->bss_type != BSS_TYPE_AP_BSS)
3726 goto out;
3727
3728 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3729
Arik Nemtsov409622e2011-02-23 00:22:29 +02003730 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003731 if (ret < 0)
3732 goto out;
3733
Ido Yariva6208652011-03-01 15:14:41 +02003734 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003735 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003736 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003737
Eliad Pellerc690ec82011-08-14 13:17:07 +03003738 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003739 if (ret < 0)
3740 goto out_sleep;
3741
Eliad Pellerb67476e2011-08-14 13:17:23 +03003742 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3743 if (ret < 0)
3744 goto out_sleep;
3745
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003746 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3747 if (ret < 0)
3748 goto out_sleep;
3749
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003750out_sleep:
3751 wl1271_ps_elp_sleep(wl);
3752
Arik Nemtsov409622e2011-02-23 00:22:29 +02003753out_free_sta:
3754 if (ret < 0)
3755 wl1271_free_sta(wl, hlid);
3756
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003757out:
3758 mutex_unlock(&wl->mutex);
3759 return ret;
3760}
3761
3762static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3763 struct ieee80211_vif *vif,
3764 struct ieee80211_sta *sta)
3765{
3766 struct wl1271 *wl = hw->priv;
3767 struct wl1271_station *wl_sta;
3768 int ret = 0, id;
3769
3770 mutex_lock(&wl->mutex);
3771
3772 if (unlikely(wl->state == WL1271_STATE_OFF))
3773 goto out;
3774
3775 if (wl->bss_type != BSS_TYPE_AP_BSS)
3776 goto out;
3777
3778 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3779
3780 wl_sta = (struct wl1271_station *)sta->drv_priv;
3781 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3782 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3783 goto out;
3784
Ido Yariva6208652011-03-01 15:14:41 +02003785 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003786 if (ret < 0)
3787 goto out;
3788
Eliad Pellerc690ec82011-08-14 13:17:07 +03003789 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003790 if (ret < 0)
3791 goto out_sleep;
3792
Arik Nemtsov409622e2011-02-23 00:22:29 +02003793 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003794
3795out_sleep:
3796 wl1271_ps_elp_sleep(wl);
3797
3798out:
3799 mutex_unlock(&wl->mutex);
3800 return ret;
3801}
3802
Luciano Coelho4623ec72011-03-21 19:26:41 +02003803static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3804 struct ieee80211_vif *vif,
3805 enum ieee80211_ampdu_mlme_action action,
3806 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3807 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003808{
3809 struct wl1271 *wl = hw->priv;
3810 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003811 u8 hlid, *ba_bitmap;
3812
3813 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3814 tid);
3815
3816 /* sanity check - the fields in FW are only 8bits wide */
3817 if (WARN_ON(tid > 0xFF))
3818 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003819
3820 mutex_lock(&wl->mutex);
3821
3822 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3823 ret = -EAGAIN;
3824 goto out;
3825 }
3826
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003827 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3828 hlid = wl->sta_hlid;
3829 ba_bitmap = &wl->ba_rx_bitmap;
3830 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3831 struct wl1271_station *wl_sta;
3832
3833 wl_sta = (struct wl1271_station *)sta->drv_priv;
3834 hlid = wl_sta->hlid;
3835 ba_bitmap = &wl->links[hlid].ba_bitmap;
3836 } else {
3837 ret = -EINVAL;
3838 goto out;
3839 }
3840
Ido Yariva6208652011-03-01 15:14:41 +02003841 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003842 if (ret < 0)
3843 goto out;
3844
Shahar Levi70559a02011-05-22 16:10:22 +03003845 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3846 tid, action);
3847
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003848 switch (action) {
3849 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003850 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003851 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003852 break;
3853 }
3854
3855 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3856 ret = -EBUSY;
3857 wl1271_error("exceeded max RX BA sessions");
3858 break;
3859 }
3860
3861 if (*ba_bitmap & BIT(tid)) {
3862 ret = -EINVAL;
3863 wl1271_error("cannot enable RX BA session on active "
3864 "tid: %d", tid);
3865 break;
3866 }
3867
3868 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3869 hlid);
3870 if (!ret) {
3871 *ba_bitmap |= BIT(tid);
3872 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003873 }
3874 break;
3875
3876 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003877 if (!(*ba_bitmap & BIT(tid))) {
3878 ret = -EINVAL;
3879 wl1271_error("no active RX BA session on tid: %d",
3880 tid);
3881 break;
3882 }
3883
3884 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3885 hlid);
3886 if (!ret) {
3887 *ba_bitmap &= ~BIT(tid);
3888 wl->ba_rx_session_count--;
3889 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003890 break;
3891
3892 /*
3893 * The BA initiator session management in FW independently.
3894 * Falling break here on purpose for all TX APDU commands.
3895 */
3896 case IEEE80211_AMPDU_TX_START:
3897 case IEEE80211_AMPDU_TX_STOP:
3898 case IEEE80211_AMPDU_TX_OPERATIONAL:
3899 ret = -EINVAL;
3900 break;
3901
3902 default:
3903 wl1271_error("Incorrect ampdu action id=%x\n", action);
3904 ret = -EINVAL;
3905 }
3906
3907 wl1271_ps_elp_sleep(wl);
3908
3909out:
3910 mutex_unlock(&wl->mutex);
3911
3912 return ret;
3913}
3914
Arik Nemtsov33437892011-04-26 23:35:39 +03003915static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3916{
3917 struct wl1271 *wl = hw->priv;
3918 bool ret = false;
3919
3920 mutex_lock(&wl->mutex);
3921
3922 if (unlikely(wl->state == WL1271_STATE_OFF))
3923 goto out;
3924
3925 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003926 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003927
3928 /* the above is appropriate for STA mode for PS purposes */
3929 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3930
3931out:
3932 mutex_unlock(&wl->mutex);
3933
3934 return ret;
3935}
3936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003937/* can't be const, mac80211 writes to this */
3938static struct ieee80211_rate wl1271_rates[] = {
3939 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003940 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3941 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003942 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003943 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3944 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003945 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3946 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003947 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3948 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003949 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3950 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003951 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3952 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3954 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003955 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3956 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003957 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003958 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3959 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003960 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003961 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3962 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003963 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003964 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3965 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003966 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003967 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3968 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003969 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003970 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3971 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003972 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003973 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3974 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003975 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003976 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3977 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003978};
3979
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003980/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003981static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003982 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003983 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003984 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3985 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3986 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003987 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003988 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3989 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3990 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003991 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003992 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3993 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3994 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003995 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003996};
3997
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003998/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003999static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004000 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004001 7, /* CONF_HW_RXTX_RATE_MCS7 */
4002 6, /* CONF_HW_RXTX_RATE_MCS6 */
4003 5, /* CONF_HW_RXTX_RATE_MCS5 */
4004 4, /* CONF_HW_RXTX_RATE_MCS4 */
4005 3, /* CONF_HW_RXTX_RATE_MCS3 */
4006 2, /* CONF_HW_RXTX_RATE_MCS2 */
4007 1, /* CONF_HW_RXTX_RATE_MCS1 */
4008 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004009
4010 11, /* CONF_HW_RXTX_RATE_54 */
4011 10, /* CONF_HW_RXTX_RATE_48 */
4012 9, /* CONF_HW_RXTX_RATE_36 */
4013 8, /* CONF_HW_RXTX_RATE_24 */
4014
4015 /* TI-specific rate */
4016 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4017
4018 7, /* CONF_HW_RXTX_RATE_18 */
4019 6, /* CONF_HW_RXTX_RATE_12 */
4020 3, /* CONF_HW_RXTX_RATE_11 */
4021 5, /* CONF_HW_RXTX_RATE_9 */
4022 4, /* CONF_HW_RXTX_RATE_6 */
4023 2, /* CONF_HW_RXTX_RATE_5_5 */
4024 1, /* CONF_HW_RXTX_RATE_2 */
4025 0 /* CONF_HW_RXTX_RATE_1 */
4026};
4027
Shahar Levie8b03a22010-10-13 16:09:39 +02004028/* 11n STA capabilities */
4029#define HW_RX_HIGHEST_RATE 72
4030
Shahar Levi00d20102010-11-08 11:20:10 +00004031#ifdef CONFIG_WL12XX_HT
4032#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004033 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4034 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004035 .ht_supported = true, \
4036 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4037 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4038 .mcs = { \
4039 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4040 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4041 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4042 }, \
4043}
Shahar Levi18357852010-10-13 16:09:41 +02004044#else
Shahar Levi00d20102010-11-08 11:20:10 +00004045#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02004046 .ht_supported = false, \
4047}
4048#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02004049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004050/* can't be const, mac80211 writes to this */
4051static struct ieee80211_supported_band wl1271_band_2ghz = {
4052 .channels = wl1271_channels,
4053 .n_channels = ARRAY_SIZE(wl1271_channels),
4054 .bitrates = wl1271_rates,
4055 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004056 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004057};
4058
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004059/* 5 GHz data rates for WL1273 */
4060static struct ieee80211_rate wl1271_rates_5ghz[] = {
4061 { .bitrate = 60,
4062 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4063 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4064 { .bitrate = 90,
4065 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4066 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4067 { .bitrate = 120,
4068 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4069 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4070 { .bitrate = 180,
4071 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4072 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4073 { .bitrate = 240,
4074 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4075 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4076 { .bitrate = 360,
4077 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4078 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4079 { .bitrate = 480,
4080 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4081 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4082 { .bitrate = 540,
4083 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4084 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4085};
4086
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004087/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004088static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004089 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4090 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4091 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4092 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4093 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4094 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4095 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4096 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4097 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4098 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4099 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4100 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4101 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4102 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4103 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4104 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4105 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4106 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4107 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4108 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4109 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4110 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4111 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4112 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4113 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4114 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4115 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4116 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4117 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4118 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4119 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4120 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4121 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4122 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004123};
4124
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004125/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004126static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004127 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004128 7, /* CONF_HW_RXTX_RATE_MCS7 */
4129 6, /* CONF_HW_RXTX_RATE_MCS6 */
4130 5, /* CONF_HW_RXTX_RATE_MCS5 */
4131 4, /* CONF_HW_RXTX_RATE_MCS4 */
4132 3, /* CONF_HW_RXTX_RATE_MCS3 */
4133 2, /* CONF_HW_RXTX_RATE_MCS2 */
4134 1, /* CONF_HW_RXTX_RATE_MCS1 */
4135 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004136
4137 7, /* CONF_HW_RXTX_RATE_54 */
4138 6, /* CONF_HW_RXTX_RATE_48 */
4139 5, /* CONF_HW_RXTX_RATE_36 */
4140 4, /* CONF_HW_RXTX_RATE_24 */
4141
4142 /* TI-specific rate */
4143 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4144
4145 3, /* CONF_HW_RXTX_RATE_18 */
4146 2, /* CONF_HW_RXTX_RATE_12 */
4147 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4148 1, /* CONF_HW_RXTX_RATE_9 */
4149 0, /* CONF_HW_RXTX_RATE_6 */
4150 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4151 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4152 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4153};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004154
4155static struct ieee80211_supported_band wl1271_band_5ghz = {
4156 .channels = wl1271_channels_5ghz,
4157 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4158 .bitrates = wl1271_rates_5ghz,
4159 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004160 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004161};
4162
Tobias Klausera0ea9492010-05-20 10:38:11 +02004163static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004164 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4165 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4166};
4167
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004168static const struct ieee80211_ops wl1271_ops = {
4169 .start = wl1271_op_start,
4170 .stop = wl1271_op_stop,
4171 .add_interface = wl1271_op_add_interface,
4172 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004173#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004174 .suspend = wl1271_op_suspend,
4175 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004176#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004177 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004178 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004179 .configure_filter = wl1271_op_configure_filter,
4180 .tx = wl1271_op_tx,
4181 .set_key = wl1271_op_set_key,
4182 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004183 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004184 .sched_scan_start = wl1271_op_sched_scan_start,
4185 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004186 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004187 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004188 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004189 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004190 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004191 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004192 .sta_add = wl1271_op_sta_add,
4193 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004194 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004195 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004196 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004197};
4198
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004199
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004200u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004201{
4202 u8 idx;
4203
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004204 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004205
4206 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4207 wl1271_error("Illegal RX rate from HW: %d", rate);
4208 return 0;
4209 }
4210
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004211 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004212 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4213 wl1271_error("Unsupported RX rate from HW: %d", rate);
4214 return 0;
4215 }
4216
4217 return idx;
4218}
4219
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004220static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4221 struct device_attribute *attr,
4222 char *buf)
4223{
4224 struct wl1271 *wl = dev_get_drvdata(dev);
4225 ssize_t len;
4226
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004227 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004228
4229 mutex_lock(&wl->mutex);
4230 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4231 wl->sg_enabled);
4232 mutex_unlock(&wl->mutex);
4233
4234 return len;
4235
4236}
4237
4238static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4239 struct device_attribute *attr,
4240 const char *buf, size_t count)
4241{
4242 struct wl1271 *wl = dev_get_drvdata(dev);
4243 unsigned long res;
4244 int ret;
4245
Luciano Coelho6277ed62011-04-01 17:49:54 +03004246 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004247 if (ret < 0) {
4248 wl1271_warning("incorrect value written to bt_coex_mode");
4249 return count;
4250 }
4251
4252 mutex_lock(&wl->mutex);
4253
4254 res = !!res;
4255
4256 if (res == wl->sg_enabled)
4257 goto out;
4258
4259 wl->sg_enabled = res;
4260
4261 if (wl->state == WL1271_STATE_OFF)
4262 goto out;
4263
Ido Yariva6208652011-03-01 15:14:41 +02004264 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004265 if (ret < 0)
4266 goto out;
4267
4268 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4269 wl1271_ps_elp_sleep(wl);
4270
4271 out:
4272 mutex_unlock(&wl->mutex);
4273 return count;
4274}
4275
4276static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4277 wl1271_sysfs_show_bt_coex_state,
4278 wl1271_sysfs_store_bt_coex_state);
4279
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004280static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4281 struct device_attribute *attr,
4282 char *buf)
4283{
4284 struct wl1271 *wl = dev_get_drvdata(dev);
4285 ssize_t len;
4286
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004287 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004288
4289 mutex_lock(&wl->mutex);
4290 if (wl->hw_pg_ver >= 0)
4291 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4292 else
4293 len = snprintf(buf, len, "n/a\n");
4294 mutex_unlock(&wl->mutex);
4295
4296 return len;
4297}
4298
Gery Kahn6f07b722011-07-18 14:21:49 +03004299static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004300 wl1271_sysfs_show_hw_pg_ver, NULL);
4301
Ido Yariv95dac04f2011-06-06 14:57:06 +03004302static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4303 struct bin_attribute *bin_attr,
4304 char *buffer, loff_t pos, size_t count)
4305{
4306 struct device *dev = container_of(kobj, struct device, kobj);
4307 struct wl1271 *wl = dev_get_drvdata(dev);
4308 ssize_t len;
4309 int ret;
4310
4311 ret = mutex_lock_interruptible(&wl->mutex);
4312 if (ret < 0)
4313 return -ERESTARTSYS;
4314
4315 /* Let only one thread read the log at a time, blocking others */
4316 while (wl->fwlog_size == 0) {
4317 DEFINE_WAIT(wait);
4318
4319 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4320 &wait,
4321 TASK_INTERRUPTIBLE);
4322
4323 if (wl->fwlog_size != 0) {
4324 finish_wait(&wl->fwlog_waitq, &wait);
4325 break;
4326 }
4327
4328 mutex_unlock(&wl->mutex);
4329
4330 schedule();
4331 finish_wait(&wl->fwlog_waitq, &wait);
4332
4333 if (signal_pending(current))
4334 return -ERESTARTSYS;
4335
4336 ret = mutex_lock_interruptible(&wl->mutex);
4337 if (ret < 0)
4338 return -ERESTARTSYS;
4339 }
4340
4341 /* Check if the fwlog is still valid */
4342 if (wl->fwlog_size < 0) {
4343 mutex_unlock(&wl->mutex);
4344 return 0;
4345 }
4346
4347 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4348 len = min(count, (size_t)wl->fwlog_size);
4349 wl->fwlog_size -= len;
4350 memcpy(buffer, wl->fwlog, len);
4351
4352 /* Make room for new messages */
4353 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4354
4355 mutex_unlock(&wl->mutex);
4356
4357 return len;
4358}
4359
4360static struct bin_attribute fwlog_attr = {
4361 .attr = {.name = "fwlog", .mode = S_IRUSR},
4362 .read = wl1271_sysfs_read_fwlog,
4363};
4364
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004365int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004366{
4367 int ret;
4368
4369 if (wl->mac80211_registered)
4370 return 0;
4371
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004372 ret = wl1271_fetch_nvs(wl);
4373 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004374 /* NOTE: The wl->nvs->nvs element must be first, in
4375 * order to simplify the casting, we assume it is at
4376 * the beginning of the wl->nvs structure.
4377 */
4378 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004379
4380 wl->mac_addr[0] = nvs_ptr[11];
4381 wl->mac_addr[1] = nvs_ptr[10];
4382 wl->mac_addr[2] = nvs_ptr[6];
4383 wl->mac_addr[3] = nvs_ptr[5];
4384 wl->mac_addr[4] = nvs_ptr[4];
4385 wl->mac_addr[5] = nvs_ptr[3];
4386 }
4387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004388 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4389
4390 ret = ieee80211_register_hw(wl->hw);
4391 if (ret < 0) {
4392 wl1271_error("unable to register mac80211 hw: %d", ret);
4393 return ret;
4394 }
4395
4396 wl->mac80211_registered = true;
4397
Eliad Pellerd60080a2010-11-24 12:53:16 +02004398 wl1271_debugfs_init(wl);
4399
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004400 register_netdevice_notifier(&wl1271_dev_notifier);
4401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402 wl1271_notice("loaded");
4403
4404 return 0;
4405}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004406EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004407
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004408void wl1271_unregister_hw(struct wl1271 *wl)
4409{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004410 if (wl->state == WL1271_STATE_PLT)
4411 __wl1271_plt_stop(wl);
4412
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004413 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004414 ieee80211_unregister_hw(wl->hw);
4415 wl->mac80211_registered = false;
4416
4417}
4418EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4419
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004420int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004421{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004422 static const u32 cipher_suites[] = {
4423 WLAN_CIPHER_SUITE_WEP40,
4424 WLAN_CIPHER_SUITE_WEP104,
4425 WLAN_CIPHER_SUITE_TKIP,
4426 WLAN_CIPHER_SUITE_CCMP,
4427 WL1271_CIPHER_SUITE_GEM,
4428 };
4429
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004430 /* The tx descriptor buffer and the TKIP space. */
4431 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4432 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004433
4434 /* unit us */
4435 /* FIXME: find a proper value */
4436 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004437 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438
4439 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004440 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004441 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004442 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004443 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004444 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004445 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004446 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004447 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004448 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004450 wl->hw->wiphy->cipher_suites = cipher_suites;
4451 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4452
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004453 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004454 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004456 /*
4457 * Maximum length of elements in scanning probe request templates
4458 * should be the maximum length possible for a template, without
4459 * the IEEE80211 header of the template
4460 */
Eliad Peller154037d2011-08-14 13:17:12 +03004461 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004462 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004463
Luciano Coelho4a31c112011-03-21 23:16:14 +02004464 /* make sure all our channels fit in the scanned_ch bitmask */
4465 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4466 ARRAY_SIZE(wl1271_channels_5ghz) >
4467 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004468 /*
4469 * We keep local copies of the band structs because we need to
4470 * modify them on a per-device basis.
4471 */
4472 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4473 sizeof(wl1271_band_2ghz));
4474 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4475 sizeof(wl1271_band_5ghz));
4476
4477 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4478 &wl->bands[IEEE80211_BAND_2GHZ];
4479 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4480 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004481
Kalle Valo12bd8942010-03-18 12:26:33 +02004482 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004483 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004484
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004485 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4486
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004487 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004488
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004489 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4490
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004491 wl->hw->max_rx_aggregation_subframes = 8;
4492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004493 return 0;
4494}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004495EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004497#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004498
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004499struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004500{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004502 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004503 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004504 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004505 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004506
4507 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4508 if (!hw) {
4509 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004510 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004511 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004512 }
4513
Julia Lawall929ebd32010-05-15 23:16:39 +02004514 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004515 if (!plat_dev) {
4516 wl1271_error("could not allocate platform_device");
4517 ret = -ENOMEM;
4518 goto err_plat_alloc;
4519 }
4520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521 wl = hw->priv;
4522 memset(wl, 0, sizeof(*wl));
4523
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004524 INIT_LIST_HEAD(&wl->list);
4525
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004526 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004527 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004529 for (i = 0; i < NUM_TX_QUEUES; i++)
4530 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004531
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004532 for (i = 0; i < NUM_TX_QUEUES; i++)
4533 for (j = 0; j < AP_MAX_LINKS; j++)
4534 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4535
Ido Yariva6208652011-03-01 15:14:41 +02004536 skb_queue_head_init(&wl->deferred_rx_queue);
4537 skb_queue_head_init(&wl->deferred_tx_queue);
4538
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004539 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004540 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004541 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004542 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4543 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4544 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004545 INIT_WORK(&wl->rx_streaming_enable_work,
4546 wl1271_rx_streaming_enable_work);
4547 INIT_WORK(&wl->rx_streaming_disable_work,
4548 wl1271_rx_streaming_disable_work);
4549
Eliad Peller92ef8962011-06-07 12:50:46 +03004550 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4551 if (!wl->freezable_wq) {
4552 ret = -ENOMEM;
4553 goto err_hw;
4554 }
4555
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004556 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004557 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004558 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004559 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004560 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004561 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004562 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004563 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004564 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004565 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004566 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004567 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004568 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004569 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004570 wl->bss_type = MAX_BSS_TYPE;
4571 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004572 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004573 wl->ap_ps_map = 0;
4574 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004575 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004576 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004577 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004578 wl->tx_security_seq = 0;
4579 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004580 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004581 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004582 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004583 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4584 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004585 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004586 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4587 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004588 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4589 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004590 wl->fwlog_size = 0;
4591 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004592
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004593 /* The system link is always allocated */
4594 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4595
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004596 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004597 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004598 wl->tx_frames[i] = NULL;
4599
4600 spin_lock_init(&wl->wl_lock);
4601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004602 wl->state = WL1271_STATE_OFF;
4603 mutex_init(&wl->mutex);
4604
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004605 /* Apply default driver configuration. */
4606 wl1271_conf_init(wl);
4607
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004608 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4609 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4610 if (!wl->aggr_buf) {
4611 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004612 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004613 }
4614
Ido Yariv990f5de2011-03-31 10:06:59 +02004615 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4616 if (!wl->dummy_packet) {
4617 ret = -ENOMEM;
4618 goto err_aggr;
4619 }
4620
Ido Yariv95dac04f2011-06-06 14:57:06 +03004621 /* Allocate one page for the FW log */
4622 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4623 if (!wl->fwlog) {
4624 ret = -ENOMEM;
4625 goto err_dummy_packet;
4626 }
4627
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004628 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004629 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004630 if (ret) {
4631 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004632 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004633 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004634 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004635
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004636 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004637 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004638 if (ret < 0) {
4639 wl1271_error("failed to create sysfs file bt_coex_state");
4640 goto err_platform;
4641 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004642
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004643 /* Create sysfs file to get HW PG version */
4644 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4645 if (ret < 0) {
4646 wl1271_error("failed to create sysfs file hw_pg_ver");
4647 goto err_bt_coex_state;
4648 }
4649
Ido Yariv95dac04f2011-06-06 14:57:06 +03004650 /* Create sysfs file for the FW log */
4651 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4652 if (ret < 0) {
4653 wl1271_error("failed to create sysfs file fwlog");
4654 goto err_hw_pg_ver;
4655 }
4656
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004657 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004658
Ido Yariv95dac04f2011-06-06 14:57:06 +03004659err_hw_pg_ver:
4660 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4661
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004662err_bt_coex_state:
4663 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4664
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004665err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004666 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004667
Ido Yariv95dac04f2011-06-06 14:57:06 +03004668err_fwlog:
4669 free_page((unsigned long)wl->fwlog);
4670
Ido Yariv990f5de2011-03-31 10:06:59 +02004671err_dummy_packet:
4672 dev_kfree_skb(wl->dummy_packet);
4673
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004674err_aggr:
4675 free_pages((unsigned long)wl->aggr_buf, order);
4676
Eliad Peller92ef8962011-06-07 12:50:46 +03004677err_wq:
4678 destroy_workqueue(wl->freezable_wq);
4679
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004680err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004681 wl1271_debugfs_exit(wl);
4682 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004683
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004684err_plat_alloc:
4685 ieee80211_free_hw(hw);
4686
4687err_hw_alloc:
4688
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004689 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004690}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004691EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004692
4693int wl1271_free_hw(struct wl1271 *wl)
4694{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004695 /* Unblock any fwlog readers */
4696 mutex_lock(&wl->mutex);
4697 wl->fwlog_size = -1;
4698 wake_up_interruptible_all(&wl->fwlog_waitq);
4699 mutex_unlock(&wl->mutex);
4700
4701 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004702
4703 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4704
4705 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004706 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004707 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004708 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004709 free_pages((unsigned long)wl->aggr_buf,
4710 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004711 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004712
4713 wl1271_debugfs_exit(wl);
4714
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004715 vfree(wl->fw);
4716 wl->fw = NULL;
4717 kfree(wl->nvs);
4718 wl->nvs = NULL;
4719
4720 kfree(wl->fw_status);
4721 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004722 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004723
4724 ieee80211_free_hw(wl->hw);
4725
4726 return 0;
4727}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004728EXPORT_SYMBOL_GPL(wl1271_free_hw);
4729
Guy Eilam491bbd62011-01-12 10:33:29 +01004730u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004731EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004732module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004733MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4734
Ido Yariv95dac04f2011-06-06 14:57:06 +03004735module_param_named(fwlog, fwlog_param, charp, 0);
4736MODULE_PARM_DESC(keymap,
4737 "FW logger options: continuous, ondemand, dbgpins or disable");
4738
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004739MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004740MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004741MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");