blob: 48a4b9961ae6e1bea44a4985bca56e46bdf1ee32 [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>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .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_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
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 Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200217 .psm_entry_retries = 5,
218 .psm_entry_nullfunc_retries = 3,
219 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300220 .keep_alive_interval = 55000,
221 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200223 .itrim = {
224 .enable = false,
225 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200226 },
227 .pm_config = {
228 .host_clk_settling_time = 5000,
229 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 },
231 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300232 .trigger_pacing = 1,
233 .avg_weight_rssi_beacon = 20,
234 .avg_weight_rssi_data = 10,
235 .avg_weight_snr_beacon = 20,
236 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200237 },
238 .scan = {
239 .min_dwell_time_active = 7500,
240 .max_dwell_time_active = 30000,
241 .min_dwell_time_passive = 30000,
242 .max_dwell_time_passive = 60000,
243 .num_probe_reqs = 2,
244 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200245 .rf = {
246 .tx_per_channel_power_compensation_2 = {
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 },
249 .tx_per_channel_power_compensation_5 = {
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 },
254 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255};
256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200257static void __wl1271_op_remove_interface(struct wl1271 *wl);
258
259
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200260static void wl1271_device_release(struct device *dev)
261{
262
263}
264
265static struct platform_device wl1271_device = {
266 .name = "wl1271",
267 .id = -1,
268
269 /* device model insists to have a release function */
270 .dev = {
271 .release = wl1271_device_release,
272 },
273};
274
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300275static LIST_HEAD(wl_list);
276
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300277static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
278 void *arg)
279{
280 struct net_device *dev = arg;
281 struct wireless_dev *wdev;
282 struct wiphy *wiphy;
283 struct ieee80211_hw *hw;
284 struct wl1271 *wl;
285 struct wl1271 *wl_temp;
286 int ret = 0;
287
288 /* Check that this notification is for us. */
289 if (what != NETDEV_CHANGE)
290 return NOTIFY_DONE;
291
292 wdev = dev->ieee80211_ptr;
293 if (wdev == NULL)
294 return NOTIFY_DONE;
295
296 wiphy = wdev->wiphy;
297 if (wiphy == NULL)
298 return NOTIFY_DONE;
299
300 hw = wiphy_priv(wiphy);
301 if (hw == NULL)
302 return NOTIFY_DONE;
303
304 wl_temp = hw->priv;
305 list_for_each_entry(wl, &wl_list, list) {
306 if (wl == wl_temp)
307 break;
308 }
309 if (wl != wl_temp)
310 return NOTIFY_DONE;
311
312 mutex_lock(&wl->mutex);
313
314 if (wl->state == WL1271_STATE_OFF)
315 goto out;
316
317 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
318 goto out;
319
320 ret = wl1271_ps_elp_wakeup(wl, false);
321 if (ret < 0)
322 goto out;
323
324 if ((dev->operstate == IF_OPER_UP) &&
325 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
326 wl1271_cmd_set_sta_state(wl);
327 wl1271_info("Association completed.");
328 }
329
330 wl1271_ps_elp_sleep(wl);
331
332out:
333 mutex_unlock(&wl->mutex);
334
335 return NOTIFY_OK;
336}
337
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338static void wl1271_conf_init(struct wl1271 *wl)
339{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340
341 /*
342 * This function applies the default configuration to the driver. This
343 * function is invoked upon driver load (spi probe.)
344 *
345 * The configuration is stored in a run-time structure in order to
346 * facilitate for run-time adjustment of any of the parameters. Making
347 * changes to the configuration structure will apply the new values on
348 * the next interface up (wl1271_op_start.)
349 */
350
351 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300352 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300353}
354
355
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300356static int wl1271_plt_init(struct wl1271 *wl)
357{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200358 struct conf_tx_ac_category *conf_ac;
359 struct conf_tx_tid *conf_tid;
360 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200362 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200363 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200364 return ret;
365
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200366 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200367 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200368 return ret;
369
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200370 ret = wl1271_cmd_ext_radio_parms(wl);
371 if (ret < 0)
372 return ret;
373
Luciano Coelho12419cc2010-02-18 13:25:44 +0200374 ret = wl1271_init_templates_config(wl);
375 if (ret < 0)
376 return ret;
377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 ret = wl1271_acx_init_mem_config(wl);
379 if (ret < 0)
380 return ret;
381
Luciano Coelho12419cc2010-02-18 13:25:44 +0200382 /* PHY layer config */
383 ret = wl1271_init_phy_config(wl);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 ret = wl1271_acx_dco_itrim_params(wl);
388 if (ret < 0)
389 goto out_free_memmap;
390
391 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200392 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200393 if (ret < 0)
394 goto out_free_memmap;
395
396 /* Bluetooth WLAN coexistence */
397 ret = wl1271_init_pta(wl);
398 if (ret < 0)
399 goto out_free_memmap;
400
401 /* Energy detection */
402 ret = wl1271_init_energy_detection(wl);
403 if (ret < 0)
404 goto out_free_memmap;
405
406 /* Default fragmentation threshold */
407 ret = wl1271_acx_frag_threshold(wl);
408 if (ret < 0)
409 goto out_free_memmap;
410
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200411 /* Default TID/AC configuration */
412 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200413 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200414 conf_ac = &wl->conf.tx.ac_conf[i];
415 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
416 conf_ac->cw_max, conf_ac->aifsn,
417 conf_ac->tx_op_limit);
418 if (ret < 0)
419 goto out_free_memmap;
420
Luciano Coelho12419cc2010-02-18 13:25:44 +0200421 conf_tid = &wl->conf.tx.tid_conf[i];
422 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
423 conf_tid->channel_type,
424 conf_tid->tsid,
425 conf_tid->ps_scheme,
426 conf_tid->ack_policy,
427 conf_tid->apsd_conf[0],
428 conf_tid->apsd_conf[1]);
429 if (ret < 0)
430 goto out_free_memmap;
431 }
432
Luciano Coelho12419cc2010-02-18 13:25:44 +0200433 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200434 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200436 goto out_free_memmap;
437
438 /* Configure for CAM power saving (ie. always active) */
439 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
440 if (ret < 0)
441 goto out_free_memmap;
442
443 /* configure PM */
444 ret = wl1271_acx_pm_config(wl);
445 if (ret < 0)
446 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
448 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200449
450 out_free_memmap:
451 kfree(wl->target_mem_map);
452 wl->target_mem_map = NULL;
453
454 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455}
456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457static void wl1271_fw_status(struct wl1271 *wl,
458 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200460 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 u32 total = 0;
462 int i;
463
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200464 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
467 "drv_rx_counter = %d, tx_results_counter = %d)",
468 status->intr,
469 status->fw_rx_counter,
470 status->drv_rx_counter,
471 status->tx_results_counter);
472
473 /* update number of available TX blocks */
474 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300475 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
476 wl->tx_blocks_freed[i];
477
478 wl->tx_blocks_freed[i] =
479 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl->tx_blocks_available += cnt;
481 total += cnt;
482 }
483
484 /* if more blocks are available now, schedule some tx work */
485 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300486 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200489 getnstimeofday(&ts);
490 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
491 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492}
493
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200494#define WL1271_IRQ_MAX_LOOPS 10
495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496static void wl1271_irq_work(struct work_struct *work)
497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300499 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200500 int loopcount = WL1271_IRQ_MAX_LOOPS;
501 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 struct wl1271 *wl =
503 container_of(work, struct wl1271, irq_work);
504
505 mutex_lock(&wl->mutex);
506
507 wl1271_debug(DEBUG_IRQ, "IRQ work");
508
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 goto out;
511
512 ret = wl1271_ps_elp_wakeup(wl, true);
513 if (ret < 0)
514 goto out;
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516 spin_lock_irqsave(&wl->wl_lock, flags);
517 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
518 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520 loopcount--;
521
522 wl1271_fw_status(wl, wl->fw_status);
523 intr = le32_to_cpu(wl->fw_status->intr);
524 if (!intr) {
525 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200526 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200527 continue;
528 }
529
530 intr &= WL1271_INTR_MASK;
531
532 if (intr & WL1271_ACX_INTR_DATA) {
533 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
534
535 /* check for tx results */
536 if (wl->fw_status->tx_results_counter !=
537 (wl->tx_results_count & 0xff))
538 wl1271_tx_complete(wl);
539
540 wl1271_rx(wl, wl->fw_status);
541 }
542
543 if (intr & WL1271_ACX_INTR_EVENT_A) {
544 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
545 wl1271_event_handle(wl, 0);
546 }
547
548 if (intr & WL1271_ACX_INTR_EVENT_B) {
549 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
550 wl1271_event_handle(wl, 1);
551 }
552
553 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
554 wl1271_debug(DEBUG_IRQ,
555 "WL1271_ACX_INTR_INIT_COMPLETE");
556
557 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
558 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
559
560 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561 }
562
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200563 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
564 ieee80211_queue_work(wl->hw, &wl->irq_work);
565 else
566 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
567 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300568
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569 wl1271_ps_elp_sleep(wl);
570
571out:
572 mutex_unlock(&wl->mutex);
573}
574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575static int wl1271_fetch_firmware(struct wl1271 *wl)
576{
577 const struct firmware *fw;
578 int ret;
579
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200580 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581
582 if (ret < 0) {
583 wl1271_error("could not get firmware: %d", ret);
584 return ret;
585 }
586
587 if (fw->size % 4) {
588 wl1271_error("firmware size is not multiple of 32 bits: %zu",
589 fw->size);
590 ret = -EILSEQ;
591 goto out;
592 }
593
594 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300595 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596
597 if (!wl->fw) {
598 wl1271_error("could not allocate memory for the firmware");
599 ret = -ENOMEM;
600 goto out;
601 }
602
603 memcpy(wl->fw, fw->data, wl->fw_len);
604
605 ret = 0;
606
607out:
608 release_firmware(fw);
609
610 return ret;
611}
612
613static int wl1271_fetch_nvs(struct wl1271 *wl)
614{
615 const struct firmware *fw;
616 int ret;
617
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200618 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619
620 if (ret < 0) {
621 wl1271_error("could not get nvs file: %d", ret);
622 return ret;
623 }
624
Julia Lawall929ebd32010-05-15 23:16:39 +0200625 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 if (!wl->nvs) {
628 wl1271_error("could not allocate memory for the nvs file");
629 ret = -ENOMEM;
630 goto out;
631 }
632
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200633 wl->nvs_len = fw->size;
634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635out:
636 release_firmware(fw);
637
638 return ret;
639}
640
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200641static void wl1271_recovery_work(struct work_struct *work)
642{
643 struct wl1271 *wl =
644 container_of(work, struct wl1271, recovery_work);
645
646 mutex_lock(&wl->mutex);
647
648 if (wl->state != WL1271_STATE_ON)
649 goto out;
650
651 wl1271_info("Hardware recovery in progress.");
652
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200653 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
654 ieee80211_connection_loss(wl->vif);
655
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200656 /* reboot the chipset */
657 __wl1271_op_remove_interface(wl);
658 ieee80211_restart_hw(wl->hw);
659
660out:
661 mutex_unlock(&wl->mutex);
662}
663
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664static void wl1271_fw_wakeup(struct wl1271 *wl)
665{
666 u32 elp_reg;
667
668 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300669 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670}
671
672static int wl1271_setup(struct wl1271 *wl)
673{
674 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
675 if (!wl->fw_status)
676 return -ENOMEM;
677
678 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
679 if (!wl->tx_res_if) {
680 kfree(wl->fw_status);
681 return -ENOMEM;
682 }
683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684 return 0;
685}
686
687static int wl1271_chip_wakeup(struct wl1271 *wl)
688{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300689 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 int ret = 0;
691
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200692 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200693 ret = wl1271_power_on(wl);
694 if (ret < 0)
695 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200697 wl1271_io_reset(wl);
698 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699
700 /* We don't need a real memory partition here, because we only want
701 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300702 memset(&partition, 0, sizeof(partition));
703 partition.reg.start = REGISTERS_BASE;
704 partition.reg.size = REGISTERS_DOWN_SIZE;
705 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706
707 /* ELP module wake up */
708 wl1271_fw_wakeup(wl);
709
710 /* whal_FwCtrl_BootSm() */
711
712 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200713 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714
715 /* 1. check if chip id is valid */
716
717 switch (wl->chip.id) {
718 case CHIP_ID_1271_PG10:
719 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
720 wl->chip.id);
721
722 ret = wl1271_setup(wl);
723 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200724 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725 break;
726 case CHIP_ID_1271_PG20:
727 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
728 wl->chip.id);
729
730 ret = wl1271_setup(wl);
731 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200732 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733 break;
734 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200735 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200737 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738 }
739
740 if (wl->fw == NULL) {
741 ret = wl1271_fetch_firmware(wl);
742 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200743 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 }
745
746 /* No NVS from netlink, try to get it from the filesystem */
747 if (wl->nvs == NULL) {
748 ret = wl1271_fetch_nvs(wl);
749 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200750 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300751 }
752
753out:
754 return ret;
755}
756
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757int wl1271_plt_start(struct wl1271 *wl)
758{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200759 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760 int ret;
761
762 mutex_lock(&wl->mutex);
763
764 wl1271_notice("power up");
765
766 if (wl->state != WL1271_STATE_OFF) {
767 wl1271_error("cannot go into PLT state because not "
768 "in off state: %d", wl->state);
769 ret = -EBUSY;
770 goto out;
771 }
772
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200773 while (retries) {
774 retries--;
775 ret = wl1271_chip_wakeup(wl);
776 if (ret < 0)
777 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200779 ret = wl1271_boot(wl);
780 if (ret < 0)
781 goto power_off;
782
783 ret = wl1271_plt_init(wl);
784 if (ret < 0)
785 goto irq_disable;
786
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200787 wl->state = WL1271_STATE_PLT;
788 wl1271_notice("firmware booted in PLT mode (%s)",
789 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 goto out;
791
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200792irq_disable:
793 wl1271_disable_interrupts(wl);
794 mutex_unlock(&wl->mutex);
795 /* Unlocking the mutex in the middle of handling is
796 inherently unsafe. In this case we deem it safe to do,
797 because we need to let any possibly pending IRQ out of
798 the system (and while we are WL1271_STATE_OFF the IRQ
799 work function will not do anything.) Also, any other
800 possible concurrent operations will fail due to the
801 current state, hence the wl1271 struct should be safe. */
802 cancel_work_sync(&wl->irq_work);
803 mutex_lock(&wl->mutex);
804power_off:
805 wl1271_power_off(wl);
806 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200808 wl1271_error("firmware boot in PLT mode failed despite %d retries",
809 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810out:
811 mutex_unlock(&wl->mutex);
812
813 return ret;
814}
815
816int wl1271_plt_stop(struct wl1271 *wl)
817{
818 int ret = 0;
819
820 mutex_lock(&wl->mutex);
821
822 wl1271_notice("power down");
823
824 if (wl->state != WL1271_STATE_PLT) {
825 wl1271_error("cannot power down because not in PLT "
826 "state: %d", wl->state);
827 ret = -EBUSY;
828 goto out;
829 }
830
831 wl1271_disable_interrupts(wl);
832 wl1271_power_off(wl);
833
834 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300835 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
837out:
838 mutex_unlock(&wl->mutex);
839
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200840 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200841 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 return ret;
844}
845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
847{
848 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200849 struct ieee80211_conf *conf = &hw->conf;
850 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
851 struct ieee80211_sta *sta = txinfo->control.sta;
852 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200854 /* peek into the rates configured in the STA entry */
855 spin_lock_irqsave(&wl->wl_lock, flags);
856 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
857 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
858 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
859 }
860 spin_unlock_irqrestore(&wl->wl_lock, flags);
861
862 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863 skb_queue_tail(&wl->tx_queue, skb);
864
865 /*
866 * The chip specific setup must run before the first TX packet -
867 * before that, the tx_work will not be initialized!
868 */
869
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300870 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871
872 /*
873 * The workqueue is slow to process the tx_queue and we need stop
874 * the queue here, otherwise the queue will get too long.
875 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200876 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
877 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200879 spin_lock_irqsave(&wl->wl_lock, flags);
880 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200881 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200882 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883 }
884
885 return NETDEV_TX_OK;
886}
887
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300888static struct notifier_block wl1271_dev_notifier = {
889 .notifier_call = wl1271_dev_notify,
890};
891
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892static int wl1271_op_start(struct ieee80211_hw *hw)
893{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200894 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
895
896 /*
897 * We have to delay the booting of the hardware because
898 * we need to know the local MAC address before downloading and
899 * initializing the firmware. The MAC address cannot be changed
900 * after boot, and without the proper MAC address, the firmware
901 * will not function properly.
902 *
903 * The MAC address is first known when the corresponding interface
904 * is added. That is where we will initialize the hardware.
905 */
906
907 return 0;
908}
909
910static void wl1271_op_stop(struct ieee80211_hw *hw)
911{
912 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
913}
914
915static int wl1271_op_add_interface(struct ieee80211_hw *hw,
916 struct ieee80211_vif *vif)
917{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400919 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200920 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 int ret = 0;
922
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200923 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
924 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925
926 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200927 if (wl->vif) {
928 ret = -EBUSY;
929 goto out;
930 }
931
932 wl->vif = vif;
933
934 switch (vif->type) {
935 case NL80211_IFTYPE_STATION:
936 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200937 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200938 break;
939 case NL80211_IFTYPE_ADHOC:
940 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200941 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200942 break;
943 default:
944 ret = -EOPNOTSUPP;
945 goto out;
946 }
947
948 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949
950 if (wl->state != WL1271_STATE_OFF) {
951 wl1271_error("cannot start because not in off state: %d",
952 wl->state);
953 ret = -EBUSY;
954 goto out;
955 }
956
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200957 while (retries) {
958 retries--;
959 ret = wl1271_chip_wakeup(wl);
960 if (ret < 0)
961 goto power_off;
962
963 ret = wl1271_boot(wl);
964 if (ret < 0)
965 goto power_off;
966
967 ret = wl1271_hw_init(wl);
968 if (ret < 0)
969 goto irq_disable;
970
971 wl->state = WL1271_STATE_ON;
972 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400973
974 /* update hw/fw version info in wiphy struct */
975 wiphy->hw_version = wl->chip.id;
976 strncpy(wiphy->fw_version, wl->chip.fw_ver,
977 sizeof(wiphy->fw_version));
978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 goto out;
980
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981irq_disable:
982 wl1271_disable_interrupts(wl);
983 mutex_unlock(&wl->mutex);
984 /* Unlocking the mutex in the middle of handling is
985 inherently unsafe. In this case we deem it safe to do,
986 because we need to let any possibly pending IRQ out of
987 the system (and while we are WL1271_STATE_OFF the IRQ
988 work function will not do anything.) Also, any other
989 possible concurrent operations will fail due to the
990 current state, hence the wl1271 struct should be safe. */
991 cancel_work_sync(&wl->irq_work);
992 mutex_lock(&wl->mutex);
993power_off:
994 wl1271_power_off(wl);
995 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997 wl1271_error("firmware boot failed despite %d retries",
998 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300999out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 mutex_unlock(&wl->mutex);
1001
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001002 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001003 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006}
1007
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001008static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 int i;
1011
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001012 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001014 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001016 list_del(&wl->list);
1017
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 WARN_ON(wl->state != WL1271_STATE_ON);
1019
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001020 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001021 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001022 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001023
Luciano Coelho08688d62010-07-08 17:50:07 +03001024 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001025 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1026 kfree(wl->scan.scanned_ch);
1027 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001028 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 }
1030
1031 wl->state = WL1271_STATE_OFF;
1032
1033 wl1271_disable_interrupts(wl);
1034
1035 mutex_unlock(&wl->mutex);
1036
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001037 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 cancel_work_sync(&wl->irq_work);
1039 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001040 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001041 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042
1043 mutex_lock(&wl->mutex);
1044
1045 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001046 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 wl1271_power_off(wl);
1048
1049 memset(wl->bssid, 0, ETH_ALEN);
1050 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1051 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001053 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001054 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001057 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1059 wl->tx_blocks_available = 0;
1060 wl->tx_results_count = 0;
1061 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001062 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001063 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064 wl->time_offset = 0;
1065 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001066 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1067 wl->sta_rate_set = 0;
1068 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001069 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001070 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001071
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 for (i = 0; i < NUM_TX_QUEUES; i++)
1073 wl->tx_blocks_freed[i] = 0;
1074
1075 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001076
1077 kfree(wl->fw_status);
1078 wl->fw_status = NULL;
1079 kfree(wl->tx_res_if);
1080 wl->tx_res_if = NULL;
1081 kfree(wl->target_mem_map);
1082 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001083}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001084
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001085static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1086 struct ieee80211_vif *vif)
1087{
1088 struct wl1271 *wl = hw->priv;
1089
1090 mutex_lock(&wl->mutex);
1091 WARN_ON(wl->vif != vif);
1092 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001094
1095 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096}
1097
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001098static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1099{
1100 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1101 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1102
1103 /* combine requested filters with current filter config */
1104 filters = wl->filters | filters;
1105
1106 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1107
1108 if (filters & FIF_PROMISC_IN_BSS) {
1109 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1110 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1111 wl->rx_config |= CFG_BSSID_FILTER_EN;
1112 }
1113 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1114 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1115 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1116 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1117 }
1118 if (filters & FIF_OTHER_BSS) {
1119 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1120 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1121 }
1122 if (filters & FIF_CONTROL) {
1123 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1124 wl->rx_filter |= CFG_RX_CTL_EN;
1125 }
1126 if (filters & FIF_FCSFAIL) {
1127 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1128 wl->rx_filter |= CFG_RX_FCS_ERROR;
1129 }
1130}
1131
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001132static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001134 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001135 /* we need to use a dummy BSSID for now */
1136 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1137 0xad, 0xbe, 0xef };
1138
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001139 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1140
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001141 /* pass through frames from all BSS */
1142 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1143
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001144 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001145 if (ret < 0)
1146 goto out;
1147
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001148 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001149
1150out:
1151 return ret;
1152}
1153
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001154static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001155{
1156 int ret;
1157
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001158 /*
1159 * One of the side effects of the JOIN command is that is clears
1160 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1161 * to a WPA/WPA2 access point will therefore kill the data-path.
1162 * Currently there is no supported scenario for JOIN during
1163 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1164 * must be handled somehow.
1165 *
1166 */
1167 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1168 wl1271_info("JOIN while associated.");
1169
1170 if (set_assoc)
1171 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1172
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001173 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1174 if (ret < 0)
1175 goto out;
1176
1177 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1178
1179 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1180 goto out;
1181
1182 /*
1183 * The join command disable the keep-alive mode, shut down its process,
1184 * and also clear the template config, so we need to reset it all after
1185 * the join. The acx_aid starts the keep-alive process, and the order
1186 * of the commands below is relevant.
1187 */
1188 ret = wl1271_acx_keep_alive_mode(wl, true);
1189 if (ret < 0)
1190 goto out;
1191
1192 ret = wl1271_acx_aid(wl, wl->aid);
1193 if (ret < 0)
1194 goto out;
1195
1196 ret = wl1271_cmd_build_klv_null_data(wl);
1197 if (ret < 0)
1198 goto out;
1199
1200 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1201 ACX_KEEP_ALIVE_TPL_VALID);
1202 if (ret < 0)
1203 goto out;
1204
1205out:
1206 return ret;
1207}
1208
1209static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210{
1211 int ret;
1212
1213 /* to stop listening to a channel, we disconnect */
1214 ret = wl1271_cmd_disconnect(wl);
1215 if (ret < 0)
1216 goto out;
1217
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001218 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001219 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001220
1221 /* stop filterting packets based on bssid */
1222 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001223
1224out:
1225 return ret;
1226}
1227
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001228static void wl1271_set_band_rate(struct wl1271 *wl)
1229{
1230 if (wl->band == IEEE80211_BAND_2GHZ)
1231 wl->basic_rate_set = wl->conf.tx.basic_rate;
1232 else
1233 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1234}
1235
1236static u32 wl1271_min_rate_get(struct wl1271 *wl)
1237{
1238 int i;
1239 u32 rate = 0;
1240
1241 if (!wl->basic_rate_set) {
1242 WARN_ON(1);
1243 wl->basic_rate_set = wl->conf.tx.basic_rate;
1244 }
1245
1246 for (i = 0; !rate; i++) {
1247 if ((wl->basic_rate_set >> i) & 0x1)
1248 rate = 1 << i;
1249 }
1250
1251 return rate;
1252}
1253
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001254static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1255{
1256 int ret;
1257
1258 if (idle) {
1259 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1260 ret = wl1271_unjoin(wl);
1261 if (ret < 0)
1262 goto out;
1263 }
1264 wl->rate_set = wl1271_min_rate_get(wl);
1265 wl->sta_rate_set = 0;
1266 ret = wl1271_acx_rate_policies(wl);
1267 if (ret < 0)
1268 goto out;
1269 ret = wl1271_acx_keep_alive_config(
1270 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1271 ACX_KEEP_ALIVE_TPL_INVALID);
1272 if (ret < 0)
1273 goto out;
1274 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1275 } else {
1276 /* increment the session counter */
1277 wl->session_counter++;
1278 if (wl->session_counter >= SESSION_COUNTER_MAX)
1279 wl->session_counter = 0;
1280 ret = wl1271_dummy_join(wl);
1281 if (ret < 0)
1282 goto out;
1283 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1284 }
1285
1286out:
1287 return ret;
1288}
1289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1291{
1292 struct wl1271 *wl = hw->priv;
1293 struct ieee80211_conf *conf = &hw->conf;
1294 int channel, ret = 0;
1295
1296 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1297
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001298 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 channel,
1300 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001301 conf->power_level,
1302 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001304 /*
1305 * mac80211 will go to idle nearly immediately after transmitting some
1306 * frames, such as the deauth. To make sure those frames reach the air,
1307 * wait here until the TX queue is fully flushed.
1308 */
1309 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1310 (conf->flags & IEEE80211_CONF_IDLE))
1311 wl1271_tx_flush(wl);
1312
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 mutex_lock(&wl->mutex);
1314
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001315 if (unlikely(wl->state == WL1271_STATE_OFF))
1316 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001317
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 ret = wl1271_ps_elp_wakeup(wl, false);
1319 if (ret < 0)
1320 goto out;
1321
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001322 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001323 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1324 ((wl->band != conf->channel->band) ||
1325 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001326 wl->band = conf->channel->band;
1327 wl->channel = channel;
1328
1329 /*
1330 * FIXME: the mac80211 should really provide a fixed rate
1331 * to use here. for now, just use the smallest possible rate
1332 * for the band as a fixed rate for association frames and
1333 * other control messages.
1334 */
1335 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1336 wl1271_set_band_rate(wl);
1337
1338 wl->basic_rate = wl1271_min_rate_get(wl);
1339 ret = wl1271_acx_rate_policies(wl);
1340 if (ret < 0)
1341 wl1271_warning("rate policy for update channel "
1342 "failed %d", ret);
1343
1344 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001345 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001346 if (ret < 0)
1347 wl1271_warning("cmd join to update channel "
1348 "failed %d", ret);
1349 }
1350 }
1351
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001352 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001353 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1354 if (ret < 0)
1355 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 }
1357
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001358 /*
1359 * if mac80211 changes the PSM mode, make sure the mode is not
1360 * incorrectly changed after the pspoll failure active window.
1361 */
1362 if (changed & IEEE80211_CONF_CHANGE_PS)
1363 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1364
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001365 if (conf->flags & IEEE80211_CONF_PS &&
1366 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1367 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368
1369 /*
1370 * We enter PSM only if we're already associated.
1371 * If we're not, we'll enter it when joining an SSID,
1372 * through the bss_info_changed() hook.
1373 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001374 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001375 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001376 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001377 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001378 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001380 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001381 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001383 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001385 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001386 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001387 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388 }
1389
1390 if (conf->power_level != wl->power_level) {
1391 ret = wl1271_acx_tx_power(wl, conf->power_level);
1392 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001393 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394
1395 wl->power_level = conf->power_level;
1396 }
1397
1398out_sleep:
1399 wl1271_ps_elp_sleep(wl);
1400
1401out:
1402 mutex_unlock(&wl->mutex);
1403
1404 return ret;
1405}
1406
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001407struct wl1271_filter_params {
1408 bool enabled;
1409 int mc_list_length;
1410 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1411};
1412
Jiri Pirko22bedad2010-04-01 21:22:57 +00001413static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1414 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001415{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001416 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001417 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001418 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001419
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001420 if (unlikely(wl->state == WL1271_STATE_OFF))
1421 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001422
Juuso Oikarinen74441132009-10-13 12:47:53 +03001423 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001424 if (!fp) {
1425 wl1271_error("Out of memory setting filters.");
1426 return 0;
1427 }
1428
1429 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001430 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001431 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1432 fp->enabled = false;
1433 } else {
1434 fp->enabled = true;
1435 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001436 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001437 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001438 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001439 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001440 }
1441
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001442 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001443}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001445#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1446 FIF_ALLMULTI | \
1447 FIF_FCSFAIL | \
1448 FIF_BCN_PRBRESP_PROMISC | \
1449 FIF_CONTROL | \
1450 FIF_OTHER_BSS)
1451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1453 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001454 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001456 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001458 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
1460 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1461
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001462 mutex_lock(&wl->mutex);
1463
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001464 *total &= WL1271_SUPPORTED_FILTERS;
1465 changed &= WL1271_SUPPORTED_FILTERS;
1466
1467 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001468 goto out;
1469
1470 ret = wl1271_ps_elp_wakeup(wl, false);
1471 if (ret < 0)
1472 goto out;
1473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001475 if (*total & FIF_ALLMULTI)
1476 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1477 else if (fp)
1478 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1479 fp->mc_list,
1480 fp->mc_list_length);
1481 if (ret < 0)
1482 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001484 /* determine, whether supported filter values have changed */
1485 if (changed == 0)
1486 goto out_sleep;
1487
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001488 /* configure filters */
1489 wl->filters = *total;
1490 wl1271_configure_filters(wl, 0);
1491
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001492 /* apply configured filters */
1493 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1494 if (ret < 0)
1495 goto out_sleep;
1496
1497out_sleep:
1498 wl1271_ps_elp_sleep(wl);
1499
1500out:
1501 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001502 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503}
1504
1505static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1506 struct ieee80211_vif *vif,
1507 struct ieee80211_sta *sta,
1508 struct ieee80211_key_conf *key_conf)
1509{
1510 struct wl1271 *wl = hw->priv;
1511 const u8 *addr;
1512 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001513 u32 tx_seq_32 = 0;
1514 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 u8 key_type;
1516
1517 static const u8 bcast_addr[ETH_ALEN] =
1518 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1519
1520 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1521
1522 addr = sta ? sta->addr : bcast_addr;
1523
1524 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1525 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1526 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001527 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 key_conf->keylen, key_conf->flags);
1529 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1530
1531 if (is_zero_ether_addr(addr)) {
1532 /* We dont support TX only encryption */
1533 ret = -EOPNOTSUPP;
1534 goto out;
1535 }
1536
1537 mutex_lock(&wl->mutex);
1538
1539 ret = wl1271_ps_elp_wakeup(wl, false);
1540 if (ret < 0)
1541 goto out_unlock;
1542
Johannes Berg97359d12010-08-10 09:46:38 +02001543 switch (key_conf->cipher) {
1544 case WLAN_CIPHER_SUITE_WEP40:
1545 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546 key_type = KEY_WEP;
1547
1548 key_conf->hw_key_idx = key_conf->keyidx;
1549 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001550 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551 key_type = KEY_TKIP;
1552
1553 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001554 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1555 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001557 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558 key_type = KEY_AES;
1559
1560 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001561 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1562 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001563 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001564 case WL1271_CIPHER_SUITE_GEM:
1565 key_type = KEY_GEM;
1566 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1567 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1568 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001570 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571
1572 ret = -EOPNOTSUPP;
1573 goto out_sleep;
1574 }
1575
1576 switch (cmd) {
1577 case SET_KEY:
1578 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1579 key_conf->keyidx, key_type,
1580 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001581 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582 if (ret < 0) {
1583 wl1271_error("Could not add or replace key");
1584 goto out_sleep;
1585 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001586
1587 /* the default WEP key needs to be configured at least once */
1588 if (key_type == KEY_WEP) {
1589 ret = wl1271_cmd_set_default_wep_key(wl,
1590 wl->default_key);
1591 if (ret < 0)
1592 goto out_sleep;
1593 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594 break;
1595
1596 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001597 /* The wl1271 does not allow to remove unicast keys - they
1598 will be cleared automatically on next CMD_JOIN. Ignore the
1599 request silently, as we dont want the mac80211 to emit
1600 an error message. */
1601 if (!is_broadcast_ether_addr(addr))
1602 break;
1603
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1605 key_conf->keyidx, key_type,
1606 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001607 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 if (ret < 0) {
1609 wl1271_error("Could not remove key");
1610 goto out_sleep;
1611 }
1612 break;
1613
1614 default:
1615 wl1271_error("Unsupported key cmd 0x%x", cmd);
1616 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001617 break;
1618 }
1619
1620out_sleep:
1621 wl1271_ps_elp_sleep(wl);
1622
1623out_unlock:
1624 mutex_unlock(&wl->mutex);
1625
1626out:
1627 return ret;
1628}
1629
1630static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001631 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001632 struct cfg80211_scan_request *req)
1633{
1634 struct wl1271 *wl = hw->priv;
1635 int ret;
1636 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001637 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638
1639 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1640
1641 if (req->n_ssids) {
1642 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001643 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001644 }
1645
1646 mutex_lock(&wl->mutex);
1647
1648 ret = wl1271_ps_elp_wakeup(wl, false);
1649 if (ret < 0)
1650 goto out;
1651
Luciano Coelho5924f892010-08-04 03:46:22 +03001652 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653
1654 wl1271_ps_elp_sleep(wl);
1655
1656out:
1657 mutex_unlock(&wl->mutex);
1658
1659 return ret;
1660}
1661
1662static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1663{
1664 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001665 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001666
1667 mutex_lock(&wl->mutex);
1668
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001669 if (unlikely(wl->state == WL1271_STATE_OFF))
1670 goto out;
1671
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672 ret = wl1271_ps_elp_wakeup(wl, false);
1673 if (ret < 0)
1674 goto out;
1675
1676 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1677 if (ret < 0)
1678 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1679
1680 wl1271_ps_elp_sleep(wl);
1681
1682out:
1683 mutex_unlock(&wl->mutex);
1684
1685 return ret;
1686}
1687
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001688static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1689{
1690 u8 *ptr = beacon->data +
1691 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1692
1693 /* find the location of the ssid in the beacon */
1694 while (ptr < beacon->data + beacon->len) {
1695 if (ptr[0] == WLAN_EID_SSID) {
1696 wl->ssid_len = ptr[1];
1697 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1698 return;
1699 }
1700 ptr += ptr[1];
1701 }
1702 wl1271_error("ad-hoc beacon template has no SSID!\n");
1703}
1704
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001705static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1706 struct ieee80211_vif *vif,
1707 struct ieee80211_bss_conf *bss_conf,
1708 u32 changed)
1709{
1710 enum wl1271_cmd_ps_mode mode;
1711 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001712 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001713 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 int ret;
1715
1716 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1717
1718 mutex_lock(&wl->mutex);
1719
1720 ret = wl1271_ps_elp_wakeup(wl, false);
1721 if (ret < 0)
1722 goto out;
1723
Eliad Peller9ee82d52010-09-19 18:55:09 +02001724 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001725 (wl->bss_type == BSS_TYPE_IBSS)) {
1726 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1727 bss_conf->beacon_int);
1728
1729 wl->beacon_int = bss_conf->beacon_int;
1730 do_join = true;
1731 }
1732
Eliad Peller9ee82d52010-09-19 18:55:09 +02001733 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001734 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001735 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1736
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001737 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1738
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001739 if (beacon) {
1740 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001741
1742 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001743 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1744 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001745 beacon->len, 0,
1746 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001747
1748 if (ret < 0) {
1749 dev_kfree_skb(beacon);
1750 goto out_sleep;
1751 }
1752
1753 hdr = (struct ieee80211_hdr *) beacon->data;
1754 hdr->frame_control = cpu_to_le16(
1755 IEEE80211_FTYPE_MGMT |
1756 IEEE80211_STYPE_PROBE_RESP);
1757
1758 ret = wl1271_cmd_template_set(wl,
1759 CMD_TEMPL_PROBE_RESPONSE,
1760 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001761 beacon->len, 0,
1762 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001763 dev_kfree_skb(beacon);
1764 if (ret < 0)
1765 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001766
1767 /* Need to update the SSID (for filtering etc) */
1768 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001769 }
1770 }
1771
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001772 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1773 (wl->bss_type == BSS_TYPE_IBSS)) {
1774 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1775 bss_conf->enable_beacon ? "enabled" : "disabled");
1776
1777 if (bss_conf->enable_beacon)
1778 wl->set_bss_type = BSS_TYPE_IBSS;
1779 else
1780 wl->set_bss_type = BSS_TYPE_STA_BSS;
1781 do_join = true;
1782 }
1783
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001784 if (changed & BSS_CHANGED_CQM) {
1785 bool enable = false;
1786 if (bss_conf->cqm_rssi_thold)
1787 enable = true;
1788 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1789 bss_conf->cqm_rssi_thold,
1790 bss_conf->cqm_rssi_hyst);
1791 if (ret < 0)
1792 goto out;
1793 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1794 }
1795
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001796 if ((changed & BSS_CHANGED_BSSID) &&
1797 /*
1798 * Now we know the correct bssid, so we send a new join command
1799 * and enable the BSSID filter
1800 */
1801 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001802 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001803
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001804 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001805 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001806 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001807
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001808 ret = wl1271_build_qos_null_data(wl);
1809 if (ret < 0)
1810 goto out_sleep;
1811
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001812 /* filter out all packets not from this BSSID */
1813 wl1271_configure_filters(wl, 0);
1814
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001815 /* Need to update the BSSID (for filtering etc) */
1816 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001817 }
1818
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819 if (changed & BSS_CHANGED_ASSOC) {
1820 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001821 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001823 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001825 wl->ps_poll_failures = 0;
1826
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001827 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001828 * use basic rates from AP, and determine lowest rate
1829 * to use with control frames.
1830 */
1831 rates = bss_conf->basic_rates;
1832 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1833 rates);
1834 wl->basic_rate = wl1271_min_rate_get(wl);
1835 ret = wl1271_acx_rate_policies(wl);
1836 if (ret < 0)
1837 goto out_sleep;
1838
1839 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001840 * with wl1271, we don't need to update the
1841 * beacon_int and dtim_period, because the firmware
1842 * updates it by itself when the first beacon is
1843 * received after a join.
1844 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001845 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1846 if (ret < 0)
1847 goto out_sleep;
1848
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001849 /*
1850 * The SSID is intentionally set to NULL here - the
1851 * firmware will set the probe request with a
1852 * broadcast SSID regardless of what we set in the
1853 * template.
1854 */
1855 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1856 NULL, 0, wl->band);
1857
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001858 /* enable the connection monitoring feature */
1859 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 if (ret < 0)
1861 goto out_sleep;
1862
1863 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001864 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1865 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001867 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001868 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001869 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870 if (ret < 0)
1871 goto out_sleep;
1872 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001873 } else {
1874 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001875 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001876 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001877 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001878
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001879 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001880 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001881
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001882 /* revert back to minimum rates for the current band */
1883 wl1271_set_band_rate(wl);
1884 wl->basic_rate = wl1271_min_rate_get(wl);
1885 ret = wl1271_acx_rate_policies(wl);
1886 if (ret < 0)
1887 goto out_sleep;
1888
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001889 /* disable connection monitor features */
1890 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001891
1892 /* Disable the keep-alive feature */
1893 ret = wl1271_acx_keep_alive_mode(wl, false);
1894
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001895 if (ret < 0)
1896 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001899 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001901 if (changed & BSS_CHANGED_ERP_SLOT) {
1902 if (bss_conf->use_short_slot)
1903 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1904 else
1905 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1906 if (ret < 0) {
1907 wl1271_warning("Set slot time failed %d", ret);
1908 goto out_sleep;
1909 }
1910 }
1911
1912 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1913 if (bss_conf->use_short_preamble)
1914 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1915 else
1916 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1917 }
1918
1919 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1920 if (bss_conf->use_cts_prot)
1921 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1922 else
1923 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1924 if (ret < 0) {
1925 wl1271_warning("Set ctsprotect failed %d", ret);
1926 goto out_sleep;
1927 }
1928 }
1929
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001930 if (changed & BSS_CHANGED_ARP_FILTER) {
1931 __be32 addr = bss_conf->arp_addr_list[0];
1932 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1933
1934 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1935 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1936 else
1937 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1938
1939 if (ret < 0)
1940 goto out_sleep;
1941 }
1942
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001943 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001944 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001945 if (ret < 0) {
1946 wl1271_warning("cmd join failed %d", ret);
1947 goto out_sleep;
1948 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001949 }
1950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951out_sleep:
1952 wl1271_ps_elp_sleep(wl);
1953
1954out:
1955 mutex_unlock(&wl->mutex);
1956}
1957
Kalle Valoc6999d82010-02-18 13:25:41 +02001958static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1959 const struct ieee80211_tx_queue_params *params)
1960{
1961 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001962 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001963 int ret;
1964
1965 mutex_lock(&wl->mutex);
1966
1967 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1968
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001969 ret = wl1271_ps_elp_wakeup(wl, false);
1970 if (ret < 0)
1971 goto out;
1972
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001973 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001974 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1975 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001976 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001977 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001978 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001979
Kalle Valo4695dc92010-03-18 12:26:38 +02001980 if (params->uapsd)
1981 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1982 else
1983 ps_scheme = CONF_PS_SCHEME_LEGACY;
1984
Kalle Valoc6999d82010-02-18 13:25:41 +02001985 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1986 CONF_CHANNEL_TYPE_EDCF,
1987 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001988 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001989 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001990 goto out_sleep;
1991
1992out_sleep:
1993 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001994
1995out:
1996 mutex_unlock(&wl->mutex);
1997
1998 return ret;
1999}
2000
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002001static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2002{
2003
2004 struct wl1271 *wl = hw->priv;
2005 u64 mactime = ULLONG_MAX;
2006 int ret;
2007
2008 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2009
2010 mutex_lock(&wl->mutex);
2011
2012 ret = wl1271_ps_elp_wakeup(wl, false);
2013 if (ret < 0)
2014 goto out;
2015
2016 ret = wl1271_acx_tsf_info(wl, &mactime);
2017 if (ret < 0)
2018 goto out_sleep;
2019
2020out_sleep:
2021 wl1271_ps_elp_sleep(wl);
2022
2023out:
2024 mutex_unlock(&wl->mutex);
2025 return mactime;
2026}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027
John W. Linvilleece550d2010-07-28 16:41:06 -04002028static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2029 struct survey_info *survey)
2030{
2031 struct wl1271 *wl = hw->priv;
2032 struct ieee80211_conf *conf = &hw->conf;
2033
2034 if (idx != 0)
2035 return -ENOENT;
2036
2037 survey->channel = conf->channel;
2038 survey->filled = SURVEY_INFO_NOISE_DBM;
2039 survey->noise = wl->noise;
2040
2041 return 0;
2042}
2043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044/* can't be const, mac80211 writes to this */
2045static struct ieee80211_rate wl1271_rates[] = {
2046 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002047 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2048 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002050 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2051 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2053 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002054 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2055 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2057 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002058 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2059 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2061 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002062 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2063 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002065 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2066 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002068 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2069 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002071 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2072 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002074 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2075 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002077 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2078 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002079 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002080 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2081 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002083 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2084 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085};
2086
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002087/*
2088 * Can't be const, mac80211 writes to this. The order of the channels here
2089 * is designed to improve scanning.
2090 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002092 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002093 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002094 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002095 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002096 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2097 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2098 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2099 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2100 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2101 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2102 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2103 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2104 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002105};
2106
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002107/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002108static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002109 /* MCS rates are used only with 11n */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2112 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2115 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2116 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2117 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2118
2119 11, /* CONF_HW_RXTX_RATE_54 */
2120 10, /* CONF_HW_RXTX_RATE_48 */
2121 9, /* CONF_HW_RXTX_RATE_36 */
2122 8, /* CONF_HW_RXTX_RATE_24 */
2123
2124 /* TI-specific rate */
2125 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2126
2127 7, /* CONF_HW_RXTX_RATE_18 */
2128 6, /* CONF_HW_RXTX_RATE_12 */
2129 3, /* CONF_HW_RXTX_RATE_11 */
2130 5, /* CONF_HW_RXTX_RATE_9 */
2131 4, /* CONF_HW_RXTX_RATE_6 */
2132 2, /* CONF_HW_RXTX_RATE_5_5 */
2133 1, /* CONF_HW_RXTX_RATE_2 */
2134 0 /* CONF_HW_RXTX_RATE_1 */
2135};
2136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137/* can't be const, mac80211 writes to this */
2138static struct ieee80211_supported_band wl1271_band_2ghz = {
2139 .channels = wl1271_channels,
2140 .n_channels = ARRAY_SIZE(wl1271_channels),
2141 .bitrates = wl1271_rates,
2142 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2143};
2144
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002145/* 5 GHz data rates for WL1273 */
2146static struct ieee80211_rate wl1271_rates_5ghz[] = {
2147 { .bitrate = 60,
2148 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2149 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2150 { .bitrate = 90,
2151 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2152 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2153 { .bitrate = 120,
2154 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2155 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2156 { .bitrate = 180,
2157 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2158 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2159 { .bitrate = 240,
2160 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2161 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2162 { .bitrate = 360,
2163 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2164 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2165 { .bitrate = 480,
2166 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2167 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2168 { .bitrate = 540,
2169 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2170 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2171};
2172
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002173/*
2174 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2175 * The order of the channels here is designed to improve scanning.
2176 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002177static struct ieee80211_channel wl1271_channels_5ghz[] = {
2178 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002179 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002180 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002181 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002182 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002183 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002184 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002185 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002186 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002187 { .hw_value = 184, .center_freq = 4920},
2188 { .hw_value = 189, .center_freq = 4945},
2189 { .hw_value = 9, .center_freq = 5045},
2190 { .hw_value = 36, .center_freq = 5180},
2191 { .hw_value = 46, .center_freq = 5230},
2192 { .hw_value = 64, .center_freq = 5320},
2193 { .hw_value = 116, .center_freq = 5580},
2194 { .hw_value = 136, .center_freq = 5680},
2195 { .hw_value = 192, .center_freq = 4960},
2196 { .hw_value = 11, .center_freq = 5055},
2197 { .hw_value = 38, .center_freq = 5190},
2198 { .hw_value = 48, .center_freq = 5240},
2199 { .hw_value = 100, .center_freq = 5500},
2200 { .hw_value = 120, .center_freq = 5600},
2201 { .hw_value = 140, .center_freq = 5700},
2202 { .hw_value = 185, .center_freq = 4925},
2203 { .hw_value = 196, .center_freq = 4980},
2204 { .hw_value = 12, .center_freq = 5060},
2205 { .hw_value = 40, .center_freq = 5200},
2206 { .hw_value = 52, .center_freq = 5260},
2207 { .hw_value = 104, .center_freq = 5520},
2208 { .hw_value = 124, .center_freq = 5620},
2209 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002210 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002211 { .hw_value = 187, .center_freq = 4935},
2212 { .hw_value = 7, .center_freq = 5035},
2213 { .hw_value = 16, .center_freq = 5080},
2214 { .hw_value = 42, .center_freq = 5210},
2215 { .hw_value = 56, .center_freq = 5280},
2216 { .hw_value = 108, .center_freq = 5540},
2217 { .hw_value = 128, .center_freq = 5640},
2218 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002219 { .hw_value = 165, .center_freq = 5825},
2220};
2221
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002222/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002223static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002224 /* MCS rates are used only with 11n */
2225 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2226 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2227 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2228 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2229 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2230 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2231 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2232 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2233
2234 7, /* CONF_HW_RXTX_RATE_54 */
2235 6, /* CONF_HW_RXTX_RATE_48 */
2236 5, /* CONF_HW_RXTX_RATE_36 */
2237 4, /* CONF_HW_RXTX_RATE_24 */
2238
2239 /* TI-specific rate */
2240 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2241
2242 3, /* CONF_HW_RXTX_RATE_18 */
2243 2, /* CONF_HW_RXTX_RATE_12 */
2244 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2245 1, /* CONF_HW_RXTX_RATE_9 */
2246 0, /* CONF_HW_RXTX_RATE_6 */
2247 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2248 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2249 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2250};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002251
2252static struct ieee80211_supported_band wl1271_band_5ghz = {
2253 .channels = wl1271_channels_5ghz,
2254 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2255 .bitrates = wl1271_rates_5ghz,
2256 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2257};
2258
Tobias Klausera0ea9492010-05-20 10:38:11 +02002259static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002260 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2261 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2262};
2263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002264static const struct ieee80211_ops wl1271_ops = {
2265 .start = wl1271_op_start,
2266 .stop = wl1271_op_stop,
2267 .add_interface = wl1271_op_add_interface,
2268 .remove_interface = wl1271_op_remove_interface,
2269 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002270 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271 .configure_filter = wl1271_op_configure_filter,
2272 .tx = wl1271_op_tx,
2273 .set_key = wl1271_op_set_key,
2274 .hw_scan = wl1271_op_hw_scan,
2275 .bss_info_changed = wl1271_op_bss_info_changed,
2276 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002277 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002278 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002279 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002280 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281};
2282
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002283
2284u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2285{
2286 u8 idx;
2287
2288 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2289
2290 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2291 wl1271_error("Illegal RX rate from HW: %d", rate);
2292 return 0;
2293 }
2294
2295 idx = wl1271_band_rate_to_idx[wl->band][rate];
2296 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2297 wl1271_error("Unsupported RX rate from HW: %d", rate);
2298 return 0;
2299 }
2300
2301 return idx;
2302}
2303
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002304static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2305 struct device_attribute *attr,
2306 char *buf)
2307{
2308 struct wl1271 *wl = dev_get_drvdata(dev);
2309 ssize_t len;
2310
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002311 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002312
2313 mutex_lock(&wl->mutex);
2314 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2315 wl->sg_enabled);
2316 mutex_unlock(&wl->mutex);
2317
2318 return len;
2319
2320}
2321
2322static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2323 struct device_attribute *attr,
2324 const char *buf, size_t count)
2325{
2326 struct wl1271 *wl = dev_get_drvdata(dev);
2327 unsigned long res;
2328 int ret;
2329
2330 ret = strict_strtoul(buf, 10, &res);
2331
2332 if (ret < 0) {
2333 wl1271_warning("incorrect value written to bt_coex_mode");
2334 return count;
2335 }
2336
2337 mutex_lock(&wl->mutex);
2338
2339 res = !!res;
2340
2341 if (res == wl->sg_enabled)
2342 goto out;
2343
2344 wl->sg_enabled = res;
2345
2346 if (wl->state == WL1271_STATE_OFF)
2347 goto out;
2348
2349 ret = wl1271_ps_elp_wakeup(wl, false);
2350 if (ret < 0)
2351 goto out;
2352
2353 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2354 wl1271_ps_elp_sleep(wl);
2355
2356 out:
2357 mutex_unlock(&wl->mutex);
2358 return count;
2359}
2360
2361static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2362 wl1271_sysfs_show_bt_coex_state,
2363 wl1271_sysfs_store_bt_coex_state);
2364
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002365static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2366 struct device_attribute *attr,
2367 char *buf)
2368{
2369 struct wl1271 *wl = dev_get_drvdata(dev);
2370 ssize_t len;
2371
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002372 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002373
2374 mutex_lock(&wl->mutex);
2375 if (wl->hw_pg_ver >= 0)
2376 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2377 else
2378 len = snprintf(buf, len, "n/a\n");
2379 mutex_unlock(&wl->mutex);
2380
2381 return len;
2382}
2383
2384static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2385 wl1271_sysfs_show_hw_pg_ver, NULL);
2386
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002387int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388{
2389 int ret;
2390
2391 if (wl->mac80211_registered)
2392 return 0;
2393
2394 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2395
2396 ret = ieee80211_register_hw(wl->hw);
2397 if (ret < 0) {
2398 wl1271_error("unable to register mac80211 hw: %d", ret);
2399 return ret;
2400 }
2401
2402 wl->mac80211_registered = true;
2403
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002404 register_netdevice_notifier(&wl1271_dev_notifier);
2405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002406 wl1271_notice("loaded");
2407
2408 return 0;
2409}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002410EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002411
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002412void wl1271_unregister_hw(struct wl1271 *wl)
2413{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002414 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002415 ieee80211_unregister_hw(wl->hw);
2416 wl->mac80211_registered = false;
2417
2418}
2419EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2420
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002421int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002423 static const u32 cipher_suites[] = {
2424 WLAN_CIPHER_SUITE_WEP40,
2425 WLAN_CIPHER_SUITE_WEP104,
2426 WLAN_CIPHER_SUITE_TKIP,
2427 WLAN_CIPHER_SUITE_CCMP,
2428 WL1271_CIPHER_SUITE_GEM,
2429 };
2430
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002431 /* The tx descriptor buffer and the TKIP space. */
2432 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2433 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002434
2435 /* unit us */
2436 /* FIXME: find a proper value */
2437 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002438 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439
2440 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002441 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002442 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002443 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002444 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002445 IEEE80211_HW_CONNECTION_MONITOR |
2446 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002448 wl->hw->wiphy->cipher_suites = cipher_suites;
2449 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2450
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002451 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2452 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 wl->hw->wiphy->max_scan_ssids = 1;
2454 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002455 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002456
Kalle Valo12bd8942010-03-18 12:26:33 +02002457 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002458 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002459
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002460 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461
2462 return 0;
2463}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002464EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002467
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002468struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002471 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002472 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002473 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002474 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475
2476 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2477 if (!hw) {
2478 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002479 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002480 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481 }
2482
Julia Lawall929ebd32010-05-15 23:16:39 +02002483 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002484 if (!plat_dev) {
2485 wl1271_error("could not allocate platform_device");
2486 ret = -ENOMEM;
2487 goto err_plat_alloc;
2488 }
2489
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490 wl = hw->priv;
2491 memset(wl, 0, sizeof(*wl));
2492
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002493 INIT_LIST_HEAD(&wl->list);
2494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002496 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002497
2498 skb_queue_head_init(&wl->tx_queue);
2499
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002500 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002501 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002502 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2503 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2504 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2505 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002507 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002509 wl->rx_counter = 0;
2510 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2511 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002512 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002514 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002515 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002516 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2517 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002518 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002519 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002520 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002521 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002522 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002523
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002524 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 wl->tx_frames[i] = NULL;
2526
2527 spin_lock_init(&wl->wl_lock);
2528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002529 wl->state = WL1271_STATE_OFF;
2530 mutex_init(&wl->mutex);
2531
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002532 /* Apply default driver configuration. */
2533 wl1271_conf_init(wl);
2534
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002535 wl1271_debugfs_init(wl);
2536
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002537 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2538 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2539 if (!wl->aggr_buf) {
2540 ret = -ENOMEM;
2541 goto err_hw;
2542 }
2543
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002544 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002545 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002546 if (ret) {
2547 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002548 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002549 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002550 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002551
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002552 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002553 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002554 if (ret < 0) {
2555 wl1271_error("failed to create sysfs file bt_coex_state");
2556 goto err_platform;
2557 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002558
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002559 /* Create sysfs file to get HW PG version */
2560 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2561 if (ret < 0) {
2562 wl1271_error("failed to create sysfs file hw_pg_ver");
2563 goto err_bt_coex_state;
2564 }
2565
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002566 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002567
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002568err_bt_coex_state:
2569 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2570
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002571err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002572 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002573
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002574err_aggr:
2575 free_pages((unsigned long)wl->aggr_buf, order);
2576
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002577err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002578 wl1271_debugfs_exit(wl);
2579 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002580
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002581err_plat_alloc:
2582 ieee80211_free_hw(hw);
2583
2584err_hw_alloc:
2585
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002586 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002587}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002588EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002589
2590int wl1271_free_hw(struct wl1271 *wl)
2591{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002592 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002593 free_pages((unsigned long)wl->aggr_buf,
2594 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002595 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002596
2597 wl1271_debugfs_exit(wl);
2598
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002599 vfree(wl->fw);
2600 wl->fw = NULL;
2601 kfree(wl->nvs);
2602 wl->nvs = NULL;
2603
2604 kfree(wl->fw_status);
2605 kfree(wl->tx_res_if);
2606
2607 ieee80211_free_hw(wl->hw);
2608
2609 return 0;
2610}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002611EXPORT_SYMBOL_GPL(wl1271_free_hw);
2612
2613MODULE_LICENSE("GPL");
2614MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2615MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");