blob: 760a5814d4a446ffc49d07cdd2fd5fa6bb7bae93 [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 Oikarinen8a080482009-10-13 12:47:44 +0300245};
246
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200247static void __wl1271_op_remove_interface(struct wl1271 *wl);
248
249
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200250static void wl1271_device_release(struct device *dev)
251{
252
253}
254
255static struct platform_device wl1271_device = {
256 .name = "wl1271",
257 .id = -1,
258
259 /* device model insists to have a release function */
260 .dev = {
261 .release = wl1271_device_release,
262 },
263};
264
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300265static LIST_HEAD(wl_list);
266
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300267static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
268 void *arg)
269{
270 struct net_device *dev = arg;
271 struct wireless_dev *wdev;
272 struct wiphy *wiphy;
273 struct ieee80211_hw *hw;
274 struct wl1271 *wl;
275 struct wl1271 *wl_temp;
276 int ret = 0;
277
278 /* Check that this notification is for us. */
279 if (what != NETDEV_CHANGE)
280 return NOTIFY_DONE;
281
282 wdev = dev->ieee80211_ptr;
283 if (wdev == NULL)
284 return NOTIFY_DONE;
285
286 wiphy = wdev->wiphy;
287 if (wiphy == NULL)
288 return NOTIFY_DONE;
289
290 hw = wiphy_priv(wiphy);
291 if (hw == NULL)
292 return NOTIFY_DONE;
293
294 wl_temp = hw->priv;
295 list_for_each_entry(wl, &wl_list, list) {
296 if (wl == wl_temp)
297 break;
298 }
299 if (wl != wl_temp)
300 return NOTIFY_DONE;
301
302 mutex_lock(&wl->mutex);
303
304 if (wl->state == WL1271_STATE_OFF)
305 goto out;
306
307 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
308 goto out;
309
310 ret = wl1271_ps_elp_wakeup(wl, false);
311 if (ret < 0)
312 goto out;
313
314 if ((dev->operstate == IF_OPER_UP) &&
315 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
316 wl1271_cmd_set_sta_state(wl);
317 wl1271_info("Association completed.");
318 }
319
320 wl1271_ps_elp_sleep(wl);
321
322out:
323 mutex_unlock(&wl->mutex);
324
325 return NOTIFY_OK;
326}
327
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300328static void wl1271_conf_init(struct wl1271 *wl)
329{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300330
331 /*
332 * This function applies the default configuration to the driver. This
333 * function is invoked upon driver load (spi probe.)
334 *
335 * The configuration is stored in a run-time structure in order to
336 * facilitate for run-time adjustment of any of the parameters. Making
337 * changes to the configuration structure will apply the new values on
338 * the next interface up (wl1271_op_start.)
339 */
340
341 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300342 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300343}
344
345
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300346static int wl1271_plt_init(struct wl1271 *wl)
347{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200348 struct conf_tx_ac_category *conf_ac;
349 struct conf_tx_tid *conf_tid;
350 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300351
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200352 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200353 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200354 return ret;
355
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200356 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200357 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200358 return ret;
359
Luciano Coelho12419cc2010-02-18 13:25:44 +0200360 ret = wl1271_init_templates_config(wl);
361 if (ret < 0)
362 return ret;
363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300364 ret = wl1271_acx_init_mem_config(wl);
365 if (ret < 0)
366 return ret;
367
Luciano Coelho12419cc2010-02-18 13:25:44 +0200368 /* PHY layer config */
369 ret = wl1271_init_phy_config(wl);
370 if (ret < 0)
371 goto out_free_memmap;
372
373 ret = wl1271_acx_dco_itrim_params(wl);
374 if (ret < 0)
375 goto out_free_memmap;
376
377 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200378 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200379 if (ret < 0)
380 goto out_free_memmap;
381
382 /* Bluetooth WLAN coexistence */
383 ret = wl1271_init_pta(wl);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 /* Energy detection */
388 ret = wl1271_init_energy_detection(wl);
389 if (ret < 0)
390 goto out_free_memmap;
391
392 /* Default fragmentation threshold */
393 ret = wl1271_acx_frag_threshold(wl);
394 if (ret < 0)
395 goto out_free_memmap;
396
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200397 /* Default TID/AC configuration */
398 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200399 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200400 conf_ac = &wl->conf.tx.ac_conf[i];
401 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
402 conf_ac->cw_max, conf_ac->aifsn,
403 conf_ac->tx_op_limit);
404 if (ret < 0)
405 goto out_free_memmap;
406
Luciano Coelho12419cc2010-02-18 13:25:44 +0200407 conf_tid = &wl->conf.tx.tid_conf[i];
408 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
409 conf_tid->channel_type,
410 conf_tid->tsid,
411 conf_tid->ps_scheme,
412 conf_tid->ack_policy,
413 conf_tid->apsd_conf[0],
414 conf_tid->apsd_conf[1]);
415 if (ret < 0)
416 goto out_free_memmap;
417 }
418
Luciano Coelho12419cc2010-02-18 13:25:44 +0200419 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200420 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200422 goto out_free_memmap;
423
424 /* Configure for CAM power saving (ie. always active) */
425 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
426 if (ret < 0)
427 goto out_free_memmap;
428
429 /* configure PM */
430 ret = wl1271_acx_pm_config(wl);
431 if (ret < 0)
432 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433
434 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200435
436 out_free_memmap:
437 kfree(wl->target_mem_map);
438 wl->target_mem_map = NULL;
439
440 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441}
442
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300443static void wl1271_fw_status(struct wl1271 *wl,
444 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200446 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447 u32 total = 0;
448 int i;
449
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200450 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300451
452 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
453 "drv_rx_counter = %d, tx_results_counter = %d)",
454 status->intr,
455 status->fw_rx_counter,
456 status->drv_rx_counter,
457 status->tx_results_counter);
458
459 /* update number of available TX blocks */
460 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300461 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
462 wl->tx_blocks_freed[i];
463
464 wl->tx_blocks_freed[i] =
465 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466 wl->tx_blocks_available += cnt;
467 total += cnt;
468 }
469
470 /* if more blocks are available now, schedule some tx work */
471 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300472 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
474 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200475 getnstimeofday(&ts);
476 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
477 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300478}
479
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200480#define WL1271_IRQ_MAX_LOOPS 10
481
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482static void wl1271_irq_work(struct work_struct *work)
483{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300485 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200486 int loopcount = WL1271_IRQ_MAX_LOOPS;
487 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488 struct wl1271 *wl =
489 container_of(work, struct wl1271, irq_work);
490
491 mutex_lock(&wl->mutex);
492
493 wl1271_debug(DEBUG_IRQ, "IRQ work");
494
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200495 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496 goto out;
497
498 ret = wl1271_ps_elp_wakeup(wl, true);
499 if (ret < 0)
500 goto out;
501
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200502 spin_lock_irqsave(&wl->wl_lock, flags);
503 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
504 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
505 spin_unlock_irqrestore(&wl->wl_lock, flags);
506 loopcount--;
507
508 wl1271_fw_status(wl, wl->fw_status);
509 intr = le32_to_cpu(wl->fw_status->intr);
510 if (!intr) {
511 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200512 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200513 continue;
514 }
515
516 intr &= WL1271_INTR_MASK;
517
518 if (intr & WL1271_ACX_INTR_DATA) {
519 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
520
521 /* check for tx results */
522 if (wl->fw_status->tx_results_counter !=
523 (wl->tx_results_count & 0xff))
524 wl1271_tx_complete(wl);
525
526 wl1271_rx(wl, wl->fw_status);
527 }
528
529 if (intr & WL1271_ACX_INTR_EVENT_A) {
530 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
531 wl1271_event_handle(wl, 0);
532 }
533
534 if (intr & WL1271_ACX_INTR_EVENT_B) {
535 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
536 wl1271_event_handle(wl, 1);
537 }
538
539 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
540 wl1271_debug(DEBUG_IRQ,
541 "WL1271_ACX_INTR_INIT_COMPLETE");
542
543 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
544 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
545
546 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300547 }
548
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200549 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
550 ieee80211_queue_work(wl->hw, &wl->irq_work);
551 else
552 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
553 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300554
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555 wl1271_ps_elp_sleep(wl);
556
557out:
558 mutex_unlock(&wl->mutex);
559}
560
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561static int wl1271_fetch_firmware(struct wl1271 *wl)
562{
563 const struct firmware *fw;
564 int ret;
565
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200566 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300567
568 if (ret < 0) {
569 wl1271_error("could not get firmware: %d", ret);
570 return ret;
571 }
572
573 if (fw->size % 4) {
574 wl1271_error("firmware size is not multiple of 32 bits: %zu",
575 fw->size);
576 ret = -EILSEQ;
577 goto out;
578 }
579
580 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300581 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300582
583 if (!wl->fw) {
584 wl1271_error("could not allocate memory for the firmware");
585 ret = -ENOMEM;
586 goto out;
587 }
588
589 memcpy(wl->fw, fw->data, wl->fw_len);
590
591 ret = 0;
592
593out:
594 release_firmware(fw);
595
596 return ret;
597}
598
599static int wl1271_fetch_nvs(struct wl1271 *wl)
600{
601 const struct firmware *fw;
602 int ret;
603
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200604 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300605
606 if (ret < 0) {
607 wl1271_error("could not get nvs file: %d", ret);
608 return ret;
609 }
610
Julia Lawall929ebd32010-05-15 23:16:39 +0200611 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300612
613 if (!wl->nvs) {
614 wl1271_error("could not allocate memory for the nvs file");
615 ret = -ENOMEM;
616 goto out;
617 }
618
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200619 wl->nvs_len = fw->size;
620
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621out:
622 release_firmware(fw);
623
624 return ret;
625}
626
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200627static void wl1271_recovery_work(struct work_struct *work)
628{
629 struct wl1271 *wl =
630 container_of(work, struct wl1271, recovery_work);
631
632 mutex_lock(&wl->mutex);
633
634 if (wl->state != WL1271_STATE_ON)
635 goto out;
636
637 wl1271_info("Hardware recovery in progress.");
638
639 /* reboot the chipset */
640 __wl1271_op_remove_interface(wl);
641 ieee80211_restart_hw(wl->hw);
642
643out:
644 mutex_unlock(&wl->mutex);
645}
646
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647static void wl1271_fw_wakeup(struct wl1271 *wl)
648{
649 u32 elp_reg;
650
651 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300652 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653}
654
655static int wl1271_setup(struct wl1271 *wl)
656{
657 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
658 if (!wl->fw_status)
659 return -ENOMEM;
660
661 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
662 if (!wl->tx_res_if) {
663 kfree(wl->fw_status);
664 return -ENOMEM;
665 }
666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 return 0;
668}
669
670static int wl1271_chip_wakeup(struct wl1271 *wl)
671{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300672 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 int ret = 0;
674
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200675 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200676 ret = wl1271_power_on(wl);
677 if (ret < 0)
678 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200680 wl1271_io_reset(wl);
681 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682
683 /* We don't need a real memory partition here, because we only want
684 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300685 memset(&partition, 0, sizeof(partition));
686 partition.reg.start = REGISTERS_BASE;
687 partition.reg.size = REGISTERS_DOWN_SIZE;
688 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689
690 /* ELP module wake up */
691 wl1271_fw_wakeup(wl);
692
693 /* whal_FwCtrl_BootSm() */
694
695 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200696 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697
698 /* 1. check if chip id is valid */
699
700 switch (wl->chip.id) {
701 case CHIP_ID_1271_PG10:
702 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
703 wl->chip.id);
704
705 ret = wl1271_setup(wl);
706 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708 break;
709 case CHIP_ID_1271_PG20:
710 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
711 wl->chip.id);
712
713 ret = wl1271_setup(wl);
714 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200715 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 break;
717 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300719 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200720 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 }
722
723 if (wl->fw == NULL) {
724 ret = wl1271_fetch_firmware(wl);
725 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727 }
728
729 /* No NVS from netlink, try to get it from the filesystem */
730 if (wl->nvs == NULL) {
731 ret = wl1271_fetch_nvs(wl);
732 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200733 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734 }
735
736out:
737 return ret;
738}
739
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740int wl1271_plt_start(struct wl1271 *wl)
741{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 int ret;
744
745 mutex_lock(&wl->mutex);
746
747 wl1271_notice("power up");
748
749 if (wl->state != WL1271_STATE_OFF) {
750 wl1271_error("cannot go into PLT state because not "
751 "in off state: %d", wl->state);
752 ret = -EBUSY;
753 goto out;
754 }
755
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200756 while (retries) {
757 retries--;
758 ret = wl1271_chip_wakeup(wl);
759 if (ret < 0)
760 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200762 ret = wl1271_boot(wl);
763 if (ret < 0)
764 goto power_off;
765
766 ret = wl1271_plt_init(wl);
767 if (ret < 0)
768 goto irq_disable;
769
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200770 wl->state = WL1271_STATE_PLT;
771 wl1271_notice("firmware booted in PLT mode (%s)",
772 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773 goto out;
774
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200775irq_disable:
776 wl1271_disable_interrupts(wl);
777 mutex_unlock(&wl->mutex);
778 /* Unlocking the mutex in the middle of handling is
779 inherently unsafe. In this case we deem it safe to do,
780 because we need to let any possibly pending IRQ out of
781 the system (and while we are WL1271_STATE_OFF the IRQ
782 work function will not do anything.) Also, any other
783 possible concurrent operations will fail due to the
784 current state, hence the wl1271 struct should be safe. */
785 cancel_work_sync(&wl->irq_work);
786 mutex_lock(&wl->mutex);
787power_off:
788 wl1271_power_off(wl);
789 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200791 wl1271_error("firmware boot in PLT mode failed despite %d retries",
792 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300793out:
794 mutex_unlock(&wl->mutex);
795
796 return ret;
797}
798
799int wl1271_plt_stop(struct wl1271 *wl)
800{
801 int ret = 0;
802
803 mutex_lock(&wl->mutex);
804
805 wl1271_notice("power down");
806
807 if (wl->state != WL1271_STATE_PLT) {
808 wl1271_error("cannot power down because not in PLT "
809 "state: %d", wl->state);
810 ret = -EBUSY;
811 goto out;
812 }
813
814 wl1271_disable_interrupts(wl);
815 wl1271_power_off(wl);
816
817 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300818 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819
820out:
821 mutex_unlock(&wl->mutex);
822
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200823 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200824 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200825
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 return ret;
827}
828
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
830{
831 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200832 struct ieee80211_conf *conf = &hw->conf;
833 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
834 struct ieee80211_sta *sta = txinfo->control.sta;
835 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200837 /* peek into the rates configured in the STA entry */
838 spin_lock_irqsave(&wl->wl_lock, flags);
839 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
840 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
841 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
842 }
843 spin_unlock_irqrestore(&wl->wl_lock, flags);
844
845 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 skb_queue_tail(&wl->tx_queue, skb);
847
848 /*
849 * The chip specific setup must run before the first TX packet -
850 * before that, the tx_work will not be initialized!
851 */
852
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300853 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854
855 /*
856 * The workqueue is slow to process the tx_queue and we need stop
857 * the queue here, otherwise the queue will get too long.
858 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200859 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
860 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200862 spin_lock_irqsave(&wl->wl_lock, flags);
863 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200864 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200865 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866 }
867
868 return NETDEV_TX_OK;
869}
870
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300871static struct notifier_block wl1271_dev_notifier = {
872 .notifier_call = wl1271_dev_notify,
873};
874
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300875static int wl1271_op_start(struct ieee80211_hw *hw)
876{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200877 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
878
879 /*
880 * We have to delay the booting of the hardware because
881 * we need to know the local MAC address before downloading and
882 * initializing the firmware. The MAC address cannot be changed
883 * after boot, and without the proper MAC address, the firmware
884 * will not function properly.
885 *
886 * The MAC address is first known when the corresponding interface
887 * is added. That is where we will initialize the hardware.
888 */
889
890 return 0;
891}
892
893static void wl1271_op_stop(struct ieee80211_hw *hw)
894{
895 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
896}
897
898static int wl1271_op_add_interface(struct ieee80211_hw *hw,
899 struct ieee80211_vif *vif)
900{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400902 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200903 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904 int ret = 0;
905
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200906 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
907 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908
909 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200910 if (wl->vif) {
911 ret = -EBUSY;
912 goto out;
913 }
914
915 wl->vif = vif;
916
917 switch (vif->type) {
918 case NL80211_IFTYPE_STATION:
919 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200920 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200921 break;
922 case NL80211_IFTYPE_ADHOC:
923 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200924 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200925 break;
926 default:
927 ret = -EOPNOTSUPP;
928 goto out;
929 }
930
931 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
933 if (wl->state != WL1271_STATE_OFF) {
934 wl1271_error("cannot start because not in off state: %d",
935 wl->state);
936 ret = -EBUSY;
937 goto out;
938 }
939
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200940 while (retries) {
941 retries--;
942 ret = wl1271_chip_wakeup(wl);
943 if (ret < 0)
944 goto power_off;
945
946 ret = wl1271_boot(wl);
947 if (ret < 0)
948 goto power_off;
949
950 ret = wl1271_hw_init(wl);
951 if (ret < 0)
952 goto irq_disable;
953
954 wl->state = WL1271_STATE_ON;
955 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400956
957 /* update hw/fw version info in wiphy struct */
958 wiphy->hw_version = wl->chip.id;
959 strncpy(wiphy->fw_version, wl->chip.fw_ver,
960 sizeof(wiphy->fw_version));
961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962 goto out;
963
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200964irq_disable:
965 wl1271_disable_interrupts(wl);
966 mutex_unlock(&wl->mutex);
967 /* Unlocking the mutex in the middle of handling is
968 inherently unsafe. In this case we deem it safe to do,
969 because we need to let any possibly pending IRQ out of
970 the system (and while we are WL1271_STATE_OFF the IRQ
971 work function will not do anything.) Also, any other
972 possible concurrent operations will fail due to the
973 current state, hence the wl1271 struct should be safe. */
974 cancel_work_sync(&wl->irq_work);
975 mutex_lock(&wl->mutex);
976power_off:
977 wl1271_power_off(wl);
978 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200980 wl1271_error("firmware boot failed despite %d retries",
981 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300982out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
984
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300985 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300986 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 return ret;
989}
990
Juuso Oikarinen52a2a372010-09-21 06:23:30 +0200991static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 int i;
994
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200995 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200997 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300999 list_del(&wl->list);
1000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 WARN_ON(wl->state != WL1271_STATE_ON);
1002
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001003 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001004 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001005 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001006
Luciano Coelho08688d62010-07-08 17:50:07 +03001007 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001008 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1009 kfree(wl->scan.scanned_ch);
1010 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001011 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 }
1013
1014 wl->state = WL1271_STATE_OFF;
1015
1016 wl1271_disable_interrupts(wl);
1017
1018 mutex_unlock(&wl->mutex);
1019
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001020 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 cancel_work_sync(&wl->irq_work);
1022 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001023 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001024 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025
1026 mutex_lock(&wl->mutex);
1027
1028 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001029 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 wl1271_power_off(wl);
1031
1032 memset(wl->bssid, 0, ETH_ALEN);
1033 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1034 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001036 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001037 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038
1039 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001040 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1042 wl->tx_blocks_available = 0;
1043 wl->tx_results_count = 0;
1044 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001045 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001046 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 wl->time_offset = 0;
1048 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001049 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1050 wl->sta_rate_set = 0;
1051 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001052 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001053 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001054
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 for (i = 0; i < NUM_TX_QUEUES; i++)
1056 wl->tx_blocks_freed[i] = 0;
1057
1058 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001059
1060 kfree(wl->fw_status);
1061 wl->fw_status = NULL;
1062 kfree(wl->tx_res_if);
1063 wl->tx_res_if = NULL;
1064 kfree(wl->target_mem_map);
1065 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001066}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001067
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001068static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1069 struct ieee80211_vif *vif)
1070{
1071 struct wl1271 *wl = hw->priv;
1072
1073 mutex_lock(&wl->mutex);
1074 WARN_ON(wl->vif != vif);
1075 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001077
1078 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079}
1080
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001081static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1082{
1083 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1084 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1085
1086 /* combine requested filters with current filter config */
1087 filters = wl->filters | filters;
1088
1089 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1090
1091 if (filters & FIF_PROMISC_IN_BSS) {
1092 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1093 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1094 wl->rx_config |= CFG_BSSID_FILTER_EN;
1095 }
1096 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1097 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1098 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1099 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1100 }
1101 if (filters & FIF_OTHER_BSS) {
1102 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1103 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1104 }
1105 if (filters & FIF_CONTROL) {
1106 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1107 wl->rx_filter |= CFG_RX_CTL_EN;
1108 }
1109 if (filters & FIF_FCSFAIL) {
1110 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1111 wl->rx_filter |= CFG_RX_FCS_ERROR;
1112 }
1113}
1114
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001115static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001116{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001117 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001118 /* we need to use a dummy BSSID for now */
1119 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1120 0xad, 0xbe, 0xef };
1121
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001122 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1123
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001124 /* pass through frames from all BSS */
1125 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1126
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001127 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001128 if (ret < 0)
1129 goto out;
1130
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001131 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001132
1133out:
1134 return ret;
1135}
1136
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001137static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001138{
1139 int ret;
1140
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001141 /*
1142 * One of the side effects of the JOIN command is that is clears
1143 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1144 * to a WPA/WPA2 access point will therefore kill the data-path.
1145 * Currently there is no supported scenario for JOIN during
1146 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1147 * must be handled somehow.
1148 *
1149 */
1150 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1151 wl1271_info("JOIN while associated.");
1152
1153 if (set_assoc)
1154 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1155
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001156 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1157 if (ret < 0)
1158 goto out;
1159
1160 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1161
1162 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1163 goto out;
1164
1165 /*
1166 * The join command disable the keep-alive mode, shut down its process,
1167 * and also clear the template config, so we need to reset it all after
1168 * the join. The acx_aid starts the keep-alive process, and the order
1169 * of the commands below is relevant.
1170 */
1171 ret = wl1271_acx_keep_alive_mode(wl, true);
1172 if (ret < 0)
1173 goto out;
1174
1175 ret = wl1271_acx_aid(wl, wl->aid);
1176 if (ret < 0)
1177 goto out;
1178
1179 ret = wl1271_cmd_build_klv_null_data(wl);
1180 if (ret < 0)
1181 goto out;
1182
1183 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1184 ACX_KEEP_ALIVE_TPL_VALID);
1185 if (ret < 0)
1186 goto out;
1187
1188out:
1189 return ret;
1190}
1191
1192static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001193{
1194 int ret;
1195
1196 /* to stop listening to a channel, we disconnect */
1197 ret = wl1271_cmd_disconnect(wl);
1198 if (ret < 0)
1199 goto out;
1200
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001201 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001202 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001203
1204 /* stop filterting packets based on bssid */
1205 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001206
1207out:
1208 return ret;
1209}
1210
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001211static void wl1271_set_band_rate(struct wl1271 *wl)
1212{
1213 if (wl->band == IEEE80211_BAND_2GHZ)
1214 wl->basic_rate_set = wl->conf.tx.basic_rate;
1215 else
1216 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1217}
1218
1219static u32 wl1271_min_rate_get(struct wl1271 *wl)
1220{
1221 int i;
1222 u32 rate = 0;
1223
1224 if (!wl->basic_rate_set) {
1225 WARN_ON(1);
1226 wl->basic_rate_set = wl->conf.tx.basic_rate;
1227 }
1228
1229 for (i = 0; !rate; i++) {
1230 if ((wl->basic_rate_set >> i) & 0x1)
1231 rate = 1 << i;
1232 }
1233
1234 return rate;
1235}
1236
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001237static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1238{
1239 int ret;
1240
1241 if (idle) {
1242 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1243 ret = wl1271_unjoin(wl);
1244 if (ret < 0)
1245 goto out;
1246 }
1247 wl->rate_set = wl1271_min_rate_get(wl);
1248 wl->sta_rate_set = 0;
1249 ret = wl1271_acx_rate_policies(wl);
1250 if (ret < 0)
1251 goto out;
1252 ret = wl1271_acx_keep_alive_config(
1253 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1254 ACX_KEEP_ALIVE_TPL_INVALID);
1255 if (ret < 0)
1256 goto out;
1257 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1258 } else {
1259 /* increment the session counter */
1260 wl->session_counter++;
1261 if (wl->session_counter >= SESSION_COUNTER_MAX)
1262 wl->session_counter = 0;
1263 ret = wl1271_dummy_join(wl);
1264 if (ret < 0)
1265 goto out;
1266 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1267 }
1268
1269out:
1270 return ret;
1271}
1272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1274{
1275 struct wl1271 *wl = hw->priv;
1276 struct ieee80211_conf *conf = &hw->conf;
1277 int channel, ret = 0;
1278
1279 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1280
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001281 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282 channel,
1283 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001284 conf->power_level,
1285 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001287 /*
1288 * mac80211 will go to idle nearly immediately after transmitting some
1289 * frames, such as the deauth. To make sure those frames reach the air,
1290 * wait here until the TX queue is fully flushed.
1291 */
1292 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1293 (conf->flags & IEEE80211_CONF_IDLE))
1294 wl1271_tx_flush(wl);
1295
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 mutex_lock(&wl->mutex);
1297
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001298 if (unlikely(wl->state == WL1271_STATE_OFF))
1299 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 ret = wl1271_ps_elp_wakeup(wl, false);
1302 if (ret < 0)
1303 goto out;
1304
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001305 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001306 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1307 ((wl->band != conf->channel->band) ||
1308 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001309 wl->band = conf->channel->band;
1310 wl->channel = channel;
1311
1312 /*
1313 * FIXME: the mac80211 should really provide a fixed rate
1314 * to use here. for now, just use the smallest possible rate
1315 * for the band as a fixed rate for association frames and
1316 * other control messages.
1317 */
1318 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1319 wl1271_set_band_rate(wl);
1320
1321 wl->basic_rate = wl1271_min_rate_get(wl);
1322 ret = wl1271_acx_rate_policies(wl);
1323 if (ret < 0)
1324 wl1271_warning("rate policy for update channel "
1325 "failed %d", ret);
1326
1327 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001328 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001329 if (ret < 0)
1330 wl1271_warning("cmd join to update channel "
1331 "failed %d", ret);
1332 }
1333 }
1334
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001335 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001336 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1337 if (ret < 0)
1338 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 }
1340
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001341 /*
1342 * if mac80211 changes the PSM mode, make sure the mode is not
1343 * incorrectly changed after the pspoll failure active window.
1344 */
1345 if (changed & IEEE80211_CONF_CHANGE_PS)
1346 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1347
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001348 if (conf->flags & IEEE80211_CONF_PS &&
1349 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1350 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
1352 /*
1353 * We enter PSM only if we're already associated.
1354 * If we're not, we'll enter it when joining an SSID,
1355 * through the bss_info_changed() hook.
1356 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001357 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001358 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001359 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001360 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001361 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001363 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001364 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001366 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001368 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001369 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001370 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371 }
1372
1373 if (conf->power_level != wl->power_level) {
1374 ret = wl1271_acx_tx_power(wl, conf->power_level);
1375 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001376 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377
1378 wl->power_level = conf->power_level;
1379 }
1380
1381out_sleep:
1382 wl1271_ps_elp_sleep(wl);
1383
1384out:
1385 mutex_unlock(&wl->mutex);
1386
1387 return ret;
1388}
1389
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001390struct wl1271_filter_params {
1391 bool enabled;
1392 int mc_list_length;
1393 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1394};
1395
Jiri Pirko22bedad2010-04-01 21:22:57 +00001396static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1397 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001398{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001399 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001400 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001401 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001402
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001403 if (unlikely(wl->state == WL1271_STATE_OFF))
1404 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001405
Juuso Oikarinen74441132009-10-13 12:47:53 +03001406 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001407 if (!fp) {
1408 wl1271_error("Out of memory setting filters.");
1409 return 0;
1410 }
1411
1412 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001413 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001414 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1415 fp->enabled = false;
1416 } else {
1417 fp->enabled = true;
1418 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001419 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001420 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001421 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001422 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001423 }
1424
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001425 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001426}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001428#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1429 FIF_ALLMULTI | \
1430 FIF_FCSFAIL | \
1431 FIF_BCN_PRBRESP_PROMISC | \
1432 FIF_CONTROL | \
1433 FIF_OTHER_BSS)
1434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1436 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001437 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001439 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001441 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442
1443 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1444
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001445 mutex_lock(&wl->mutex);
1446
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001447 *total &= WL1271_SUPPORTED_FILTERS;
1448 changed &= WL1271_SUPPORTED_FILTERS;
1449
1450 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001451 goto out;
1452
1453 ret = wl1271_ps_elp_wakeup(wl, false);
1454 if (ret < 0)
1455 goto out;
1456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001458 if (*total & FIF_ALLMULTI)
1459 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1460 else if (fp)
1461 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1462 fp->mc_list,
1463 fp->mc_list_length);
1464 if (ret < 0)
1465 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001467 /* determine, whether supported filter values have changed */
1468 if (changed == 0)
1469 goto out_sleep;
1470
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001471 /* configure filters */
1472 wl->filters = *total;
1473 wl1271_configure_filters(wl, 0);
1474
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001475 /* apply configured filters */
1476 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1477 if (ret < 0)
1478 goto out_sleep;
1479
1480out_sleep:
1481 wl1271_ps_elp_sleep(wl);
1482
1483out:
1484 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001485 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486}
1487
1488static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1489 struct ieee80211_vif *vif,
1490 struct ieee80211_sta *sta,
1491 struct ieee80211_key_conf *key_conf)
1492{
1493 struct wl1271 *wl = hw->priv;
1494 const u8 *addr;
1495 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001496 u32 tx_seq_32 = 0;
1497 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 u8 key_type;
1499
1500 static const u8 bcast_addr[ETH_ALEN] =
1501 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1502
1503 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1504
1505 addr = sta ? sta->addr : bcast_addr;
1506
1507 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1508 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1509 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001510 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 key_conf->keylen, key_conf->flags);
1512 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1513
1514 if (is_zero_ether_addr(addr)) {
1515 /* We dont support TX only encryption */
1516 ret = -EOPNOTSUPP;
1517 goto out;
1518 }
1519
1520 mutex_lock(&wl->mutex);
1521
1522 ret = wl1271_ps_elp_wakeup(wl, false);
1523 if (ret < 0)
1524 goto out_unlock;
1525
Johannes Berg97359d12010-08-10 09:46:38 +02001526 switch (key_conf->cipher) {
1527 case WLAN_CIPHER_SUITE_WEP40:
1528 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 key_type = KEY_WEP;
1530
1531 key_conf->hw_key_idx = key_conf->keyidx;
1532 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001533 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534 key_type = KEY_TKIP;
1535
1536 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001537 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1538 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001540 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541 key_type = KEY_AES;
1542
1543 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001544 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1545 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001547 case WL1271_CIPHER_SUITE_GEM:
1548 key_type = KEY_GEM;
1549 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1550 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1551 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001553 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554
1555 ret = -EOPNOTSUPP;
1556 goto out_sleep;
1557 }
1558
1559 switch (cmd) {
1560 case SET_KEY:
1561 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1562 key_conf->keyidx, key_type,
1563 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001564 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565 if (ret < 0) {
1566 wl1271_error("Could not add or replace key");
1567 goto out_sleep;
1568 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001569
1570 /* the default WEP key needs to be configured at least once */
1571 if (key_type == KEY_WEP) {
1572 ret = wl1271_cmd_set_default_wep_key(wl,
1573 wl->default_key);
1574 if (ret < 0)
1575 goto out_sleep;
1576 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 break;
1578
1579 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001580 /* The wl1271 does not allow to remove unicast keys - they
1581 will be cleared automatically on next CMD_JOIN. Ignore the
1582 request silently, as we dont want the mac80211 to emit
1583 an error message. */
1584 if (!is_broadcast_ether_addr(addr))
1585 break;
1586
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1588 key_conf->keyidx, key_type,
1589 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001590 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001591 if (ret < 0) {
1592 wl1271_error("Could not remove key");
1593 goto out_sleep;
1594 }
1595 break;
1596
1597 default:
1598 wl1271_error("Unsupported key cmd 0x%x", cmd);
1599 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001600 break;
1601 }
1602
1603out_sleep:
1604 wl1271_ps_elp_sleep(wl);
1605
1606out_unlock:
1607 mutex_unlock(&wl->mutex);
1608
1609out:
1610 return ret;
1611}
1612
1613static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001614 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 struct cfg80211_scan_request *req)
1616{
1617 struct wl1271 *wl = hw->priv;
1618 int ret;
1619 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001620 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001621
1622 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1623
1624 if (req->n_ssids) {
1625 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001626 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001627 }
1628
1629 mutex_lock(&wl->mutex);
1630
1631 ret = wl1271_ps_elp_wakeup(wl, false);
1632 if (ret < 0)
1633 goto out;
1634
Luciano Coelho5924f892010-08-04 03:46:22 +03001635 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001636
1637 wl1271_ps_elp_sleep(wl);
1638
1639out:
1640 mutex_unlock(&wl->mutex);
1641
1642 return ret;
1643}
1644
1645static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1646{
1647 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001648 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649
1650 mutex_lock(&wl->mutex);
1651
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001652 if (unlikely(wl->state == WL1271_STATE_OFF))
1653 goto out;
1654
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655 ret = wl1271_ps_elp_wakeup(wl, false);
1656 if (ret < 0)
1657 goto out;
1658
1659 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1660 if (ret < 0)
1661 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1662
1663 wl1271_ps_elp_sleep(wl);
1664
1665out:
1666 mutex_unlock(&wl->mutex);
1667
1668 return ret;
1669}
1670
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001671static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1672{
1673 u8 *ptr = beacon->data +
1674 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1675
1676 /* find the location of the ssid in the beacon */
1677 while (ptr < beacon->data + beacon->len) {
1678 if (ptr[0] == WLAN_EID_SSID) {
1679 wl->ssid_len = ptr[1];
1680 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1681 return;
1682 }
1683 ptr += ptr[1];
1684 }
1685 wl1271_error("ad-hoc beacon template has no SSID!\n");
1686}
1687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1689 struct ieee80211_vif *vif,
1690 struct ieee80211_bss_conf *bss_conf,
1691 u32 changed)
1692{
1693 enum wl1271_cmd_ps_mode mode;
1694 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001695 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001696 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 int ret;
1698
1699 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1700
1701 mutex_lock(&wl->mutex);
1702
1703 ret = wl1271_ps_elp_wakeup(wl, false);
1704 if (ret < 0)
1705 goto out;
1706
Eliad Peller9ee82d52010-09-19 18:55:09 +02001707 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001708 (wl->bss_type == BSS_TYPE_IBSS)) {
1709 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1710 bss_conf->beacon_int);
1711
1712 wl->beacon_int = bss_conf->beacon_int;
1713 do_join = true;
1714 }
1715
Eliad Peller9ee82d52010-09-19 18:55:09 +02001716 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001717 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001718 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1719
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001720 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1721
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001722 if (beacon) {
1723 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001724
1725 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001726 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1727 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001728 beacon->len, 0,
1729 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001730
1731 if (ret < 0) {
1732 dev_kfree_skb(beacon);
1733 goto out_sleep;
1734 }
1735
1736 hdr = (struct ieee80211_hdr *) beacon->data;
1737 hdr->frame_control = cpu_to_le16(
1738 IEEE80211_FTYPE_MGMT |
1739 IEEE80211_STYPE_PROBE_RESP);
1740
1741 ret = wl1271_cmd_template_set(wl,
1742 CMD_TEMPL_PROBE_RESPONSE,
1743 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001744 beacon->len, 0,
1745 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001746 dev_kfree_skb(beacon);
1747 if (ret < 0)
1748 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001749
1750 /* Need to update the SSID (for filtering etc) */
1751 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001752 }
1753 }
1754
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001755 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1756 (wl->bss_type == BSS_TYPE_IBSS)) {
1757 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1758 bss_conf->enable_beacon ? "enabled" : "disabled");
1759
1760 if (bss_conf->enable_beacon)
1761 wl->set_bss_type = BSS_TYPE_IBSS;
1762 else
1763 wl->set_bss_type = BSS_TYPE_STA_BSS;
1764 do_join = true;
1765 }
1766
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001767 if (changed & BSS_CHANGED_CQM) {
1768 bool enable = false;
1769 if (bss_conf->cqm_rssi_thold)
1770 enable = true;
1771 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1772 bss_conf->cqm_rssi_thold,
1773 bss_conf->cqm_rssi_hyst);
1774 if (ret < 0)
1775 goto out;
1776 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1777 }
1778
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001779 if ((changed & BSS_CHANGED_BSSID) &&
1780 /*
1781 * Now we know the correct bssid, so we send a new join command
1782 * and enable the BSSID filter
1783 */
1784 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001785 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001786
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001787 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001788 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001789 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001790
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001791 ret = wl1271_build_qos_null_data(wl);
1792 if (ret < 0)
1793 goto out_sleep;
1794
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001795 /* filter out all packets not from this BSSID */
1796 wl1271_configure_filters(wl, 0);
1797
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001798 /* Need to update the BSSID (for filtering etc) */
1799 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001800 }
1801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 if (changed & BSS_CHANGED_ASSOC) {
1803 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001804 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001806 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001808 wl->ps_poll_failures = 0;
1809
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001810 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001811 * use basic rates from AP, and determine lowest rate
1812 * to use with control frames.
1813 */
1814 rates = bss_conf->basic_rates;
1815 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1816 rates);
1817 wl->basic_rate = wl1271_min_rate_get(wl);
1818 ret = wl1271_acx_rate_policies(wl);
1819 if (ret < 0)
1820 goto out_sleep;
1821
1822 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001823 * with wl1271, we don't need to update the
1824 * beacon_int and dtim_period, because the firmware
1825 * updates it by itself when the first beacon is
1826 * received after a join.
1827 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1829 if (ret < 0)
1830 goto out_sleep;
1831
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001832 /*
1833 * The SSID is intentionally set to NULL here - the
1834 * firmware will set the probe request with a
1835 * broadcast SSID regardless of what we set in the
1836 * template.
1837 */
1838 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1839 NULL, 0, wl->band);
1840
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001841 /* enable the connection monitoring feature */
1842 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 if (ret < 0)
1844 goto out_sleep;
1845
1846 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001847 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1848 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001850 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001851 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001852 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853 if (ret < 0)
1854 goto out_sleep;
1855 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001856 } else {
1857 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001858 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001859 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001860 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001861
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001862 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001863 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001864
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001865 /* revert back to minimum rates for the current band */
1866 wl1271_set_band_rate(wl);
1867 wl->basic_rate = wl1271_min_rate_get(wl);
1868 ret = wl1271_acx_rate_policies(wl);
1869 if (ret < 0)
1870 goto out_sleep;
1871
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001872 /* disable connection monitor features */
1873 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001874
1875 /* Disable the keep-alive feature */
1876 ret = wl1271_acx_keep_alive_mode(wl, false);
1877
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001878 if (ret < 0)
1879 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001883
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001884 if (changed & BSS_CHANGED_ERP_SLOT) {
1885 if (bss_conf->use_short_slot)
1886 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1887 else
1888 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1889 if (ret < 0) {
1890 wl1271_warning("Set slot time failed %d", ret);
1891 goto out_sleep;
1892 }
1893 }
1894
1895 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1896 if (bss_conf->use_short_preamble)
1897 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1898 else
1899 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1900 }
1901
1902 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1903 if (bss_conf->use_cts_prot)
1904 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1905 else
1906 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1907 if (ret < 0) {
1908 wl1271_warning("Set ctsprotect failed %d", ret);
1909 goto out_sleep;
1910 }
1911 }
1912
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001913 if (changed & BSS_CHANGED_ARP_FILTER) {
1914 __be32 addr = bss_conf->arp_addr_list[0];
1915 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1916
1917 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1918 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1919 else
1920 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1921
1922 if (ret < 0)
1923 goto out_sleep;
1924 }
1925
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001926 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001927 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001928 if (ret < 0) {
1929 wl1271_warning("cmd join failed %d", ret);
1930 goto out_sleep;
1931 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001932 }
1933
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934out_sleep:
1935 wl1271_ps_elp_sleep(wl);
1936
1937out:
1938 mutex_unlock(&wl->mutex);
1939}
1940
Kalle Valoc6999d82010-02-18 13:25:41 +02001941static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1942 const struct ieee80211_tx_queue_params *params)
1943{
1944 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001945 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001946 int ret;
1947
1948 mutex_lock(&wl->mutex);
1949
1950 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1951
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001952 ret = wl1271_ps_elp_wakeup(wl, false);
1953 if (ret < 0)
1954 goto out;
1955
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001956 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001957 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1958 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001959 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001960 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001961 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001962
Kalle Valo4695dc92010-03-18 12:26:38 +02001963 if (params->uapsd)
1964 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1965 else
1966 ps_scheme = CONF_PS_SCHEME_LEGACY;
1967
Kalle Valoc6999d82010-02-18 13:25:41 +02001968 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1969 CONF_CHANNEL_TYPE_EDCF,
1970 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001971 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001972 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001973 goto out_sleep;
1974
1975out_sleep:
1976 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001977
1978out:
1979 mutex_unlock(&wl->mutex);
1980
1981 return ret;
1982}
1983
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001984static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1985{
1986
1987 struct wl1271 *wl = hw->priv;
1988 u64 mactime = ULLONG_MAX;
1989 int ret;
1990
1991 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1992
1993 mutex_lock(&wl->mutex);
1994
1995 ret = wl1271_ps_elp_wakeup(wl, false);
1996 if (ret < 0)
1997 goto out;
1998
1999 ret = wl1271_acx_tsf_info(wl, &mactime);
2000 if (ret < 0)
2001 goto out_sleep;
2002
2003out_sleep:
2004 wl1271_ps_elp_sleep(wl);
2005
2006out:
2007 mutex_unlock(&wl->mutex);
2008 return mactime;
2009}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010
John W. Linvilleece550d2010-07-28 16:41:06 -04002011static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2012 struct survey_info *survey)
2013{
2014 struct wl1271 *wl = hw->priv;
2015 struct ieee80211_conf *conf = &hw->conf;
2016
2017 if (idx != 0)
2018 return -ENOENT;
2019
2020 survey->channel = conf->channel;
2021 survey->filled = SURVEY_INFO_NOISE_DBM;
2022 survey->noise = wl->noise;
2023
2024 return 0;
2025}
2026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027/* can't be const, mac80211 writes to this */
2028static struct ieee80211_rate wl1271_rates[] = {
2029 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002030 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002033 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2036 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002037 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2038 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2040 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002041 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2042 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002043 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2044 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002045 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2046 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002048 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2049 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002050 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002051 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2052 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002054 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2055 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002057 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2058 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002060 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2061 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002063 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2064 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002066 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2067 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068};
2069
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002070/*
2071 * Can't be const, mac80211 writes to this. The order of the channels here
2072 * is designed to improve scanning.
2073 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002074static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002075 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002076 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002077 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002078 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002079 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2080 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2081 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2082 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2083 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2084 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2085 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2086 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2087 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002088};
2089
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002090/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002091static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002092 /* MCS rates are used only with 11n */
2093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2094 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2095 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2096 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2099 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2101
2102 11, /* CONF_HW_RXTX_RATE_54 */
2103 10, /* CONF_HW_RXTX_RATE_48 */
2104 9, /* CONF_HW_RXTX_RATE_36 */
2105 8, /* CONF_HW_RXTX_RATE_24 */
2106
2107 /* TI-specific rate */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2109
2110 7, /* CONF_HW_RXTX_RATE_18 */
2111 6, /* CONF_HW_RXTX_RATE_12 */
2112 3, /* CONF_HW_RXTX_RATE_11 */
2113 5, /* CONF_HW_RXTX_RATE_9 */
2114 4, /* CONF_HW_RXTX_RATE_6 */
2115 2, /* CONF_HW_RXTX_RATE_5_5 */
2116 1, /* CONF_HW_RXTX_RATE_2 */
2117 0 /* CONF_HW_RXTX_RATE_1 */
2118};
2119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002120/* can't be const, mac80211 writes to this */
2121static struct ieee80211_supported_band wl1271_band_2ghz = {
2122 .channels = wl1271_channels,
2123 .n_channels = ARRAY_SIZE(wl1271_channels),
2124 .bitrates = wl1271_rates,
2125 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2126};
2127
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002128/* 5 GHz data rates for WL1273 */
2129static struct ieee80211_rate wl1271_rates_5ghz[] = {
2130 { .bitrate = 60,
2131 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2132 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2133 { .bitrate = 90,
2134 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2135 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2136 { .bitrate = 120,
2137 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2138 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2139 { .bitrate = 180,
2140 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2141 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2142 { .bitrate = 240,
2143 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2144 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2145 { .bitrate = 360,
2146 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2147 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2148 { .bitrate = 480,
2149 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2150 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2151 { .bitrate = 540,
2152 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2153 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2154};
2155
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002156/*
2157 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2158 * The order of the channels here is designed to improve scanning.
2159 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002160static struct ieee80211_channel wl1271_channels_5ghz[] = {
2161 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002162 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002163 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002164 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002165 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002166 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002167 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002168 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002169 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002170 { .hw_value = 184, .center_freq = 4920},
2171 { .hw_value = 189, .center_freq = 4945},
2172 { .hw_value = 9, .center_freq = 5045},
2173 { .hw_value = 36, .center_freq = 5180},
2174 { .hw_value = 46, .center_freq = 5230},
2175 { .hw_value = 64, .center_freq = 5320},
2176 { .hw_value = 116, .center_freq = 5580},
2177 { .hw_value = 136, .center_freq = 5680},
2178 { .hw_value = 192, .center_freq = 4960},
2179 { .hw_value = 11, .center_freq = 5055},
2180 { .hw_value = 38, .center_freq = 5190},
2181 { .hw_value = 48, .center_freq = 5240},
2182 { .hw_value = 100, .center_freq = 5500},
2183 { .hw_value = 120, .center_freq = 5600},
2184 { .hw_value = 140, .center_freq = 5700},
2185 { .hw_value = 185, .center_freq = 4925},
2186 { .hw_value = 196, .center_freq = 4980},
2187 { .hw_value = 12, .center_freq = 5060},
2188 { .hw_value = 40, .center_freq = 5200},
2189 { .hw_value = 52, .center_freq = 5260},
2190 { .hw_value = 104, .center_freq = 5520},
2191 { .hw_value = 124, .center_freq = 5620},
2192 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002193 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002194 { .hw_value = 187, .center_freq = 4935},
2195 { .hw_value = 7, .center_freq = 5035},
2196 { .hw_value = 16, .center_freq = 5080},
2197 { .hw_value = 42, .center_freq = 5210},
2198 { .hw_value = 56, .center_freq = 5280},
2199 { .hw_value = 108, .center_freq = 5540},
2200 { .hw_value = 128, .center_freq = 5640},
2201 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002202 { .hw_value = 165, .center_freq = 5825},
2203};
2204
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002205/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002206static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002207 /* MCS rates are used only with 11n */
2208 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2209 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2210 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2211 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2212 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2213 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2214 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2215 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2216
2217 7, /* CONF_HW_RXTX_RATE_54 */
2218 6, /* CONF_HW_RXTX_RATE_48 */
2219 5, /* CONF_HW_RXTX_RATE_36 */
2220 4, /* CONF_HW_RXTX_RATE_24 */
2221
2222 /* TI-specific rate */
2223 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2224
2225 3, /* CONF_HW_RXTX_RATE_18 */
2226 2, /* CONF_HW_RXTX_RATE_12 */
2227 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2228 1, /* CONF_HW_RXTX_RATE_9 */
2229 0, /* CONF_HW_RXTX_RATE_6 */
2230 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2231 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2232 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2233};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002234
2235static struct ieee80211_supported_band wl1271_band_5ghz = {
2236 .channels = wl1271_channels_5ghz,
2237 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2238 .bitrates = wl1271_rates_5ghz,
2239 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2240};
2241
Tobias Klausera0ea9492010-05-20 10:38:11 +02002242static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002243 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2244 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2245};
2246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247static const struct ieee80211_ops wl1271_ops = {
2248 .start = wl1271_op_start,
2249 .stop = wl1271_op_stop,
2250 .add_interface = wl1271_op_add_interface,
2251 .remove_interface = wl1271_op_remove_interface,
2252 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002253 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002254 .configure_filter = wl1271_op_configure_filter,
2255 .tx = wl1271_op_tx,
2256 .set_key = wl1271_op_set_key,
2257 .hw_scan = wl1271_op_hw_scan,
2258 .bss_info_changed = wl1271_op_bss_info_changed,
2259 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002260 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002261 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002262 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002263 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002264};
2265
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002266
2267u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2268{
2269 u8 idx;
2270
2271 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2272
2273 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2274 wl1271_error("Illegal RX rate from HW: %d", rate);
2275 return 0;
2276 }
2277
2278 idx = wl1271_band_rate_to_idx[wl->band][rate];
2279 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2280 wl1271_error("Unsupported RX rate from HW: %d", rate);
2281 return 0;
2282 }
2283
2284 return idx;
2285}
2286
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002287static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2288 struct device_attribute *attr,
2289 char *buf)
2290{
2291 struct wl1271 *wl = dev_get_drvdata(dev);
2292 ssize_t len;
2293
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002294 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002295
2296 mutex_lock(&wl->mutex);
2297 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2298 wl->sg_enabled);
2299 mutex_unlock(&wl->mutex);
2300
2301 return len;
2302
2303}
2304
2305static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2306 struct device_attribute *attr,
2307 const char *buf, size_t count)
2308{
2309 struct wl1271 *wl = dev_get_drvdata(dev);
2310 unsigned long res;
2311 int ret;
2312
2313 ret = strict_strtoul(buf, 10, &res);
2314
2315 if (ret < 0) {
2316 wl1271_warning("incorrect value written to bt_coex_mode");
2317 return count;
2318 }
2319
2320 mutex_lock(&wl->mutex);
2321
2322 res = !!res;
2323
2324 if (res == wl->sg_enabled)
2325 goto out;
2326
2327 wl->sg_enabled = res;
2328
2329 if (wl->state == WL1271_STATE_OFF)
2330 goto out;
2331
2332 ret = wl1271_ps_elp_wakeup(wl, false);
2333 if (ret < 0)
2334 goto out;
2335
2336 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2337 wl1271_ps_elp_sleep(wl);
2338
2339 out:
2340 mutex_unlock(&wl->mutex);
2341 return count;
2342}
2343
2344static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2345 wl1271_sysfs_show_bt_coex_state,
2346 wl1271_sysfs_store_bt_coex_state);
2347
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002348static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2349 struct device_attribute *attr,
2350 char *buf)
2351{
2352 struct wl1271 *wl = dev_get_drvdata(dev);
2353 ssize_t len;
2354
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002355 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002356
2357 mutex_lock(&wl->mutex);
2358 if (wl->hw_pg_ver >= 0)
2359 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2360 else
2361 len = snprintf(buf, len, "n/a\n");
2362 mutex_unlock(&wl->mutex);
2363
2364 return len;
2365}
2366
2367static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2368 wl1271_sysfs_show_hw_pg_ver, NULL);
2369
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002370int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371{
2372 int ret;
2373
2374 if (wl->mac80211_registered)
2375 return 0;
2376
2377 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2378
2379 ret = ieee80211_register_hw(wl->hw);
2380 if (ret < 0) {
2381 wl1271_error("unable to register mac80211 hw: %d", ret);
2382 return ret;
2383 }
2384
2385 wl->mac80211_registered = true;
2386
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002387 register_netdevice_notifier(&wl1271_dev_notifier);
2388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389 wl1271_notice("loaded");
2390
2391 return 0;
2392}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002393EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002395void wl1271_unregister_hw(struct wl1271 *wl)
2396{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002397 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002398 ieee80211_unregister_hw(wl->hw);
2399 wl->mac80211_registered = false;
2400
2401}
2402EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2403
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002404int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002406 static const u32 cipher_suites[] = {
2407 WLAN_CIPHER_SUITE_WEP40,
2408 WLAN_CIPHER_SUITE_WEP104,
2409 WLAN_CIPHER_SUITE_TKIP,
2410 WLAN_CIPHER_SUITE_CCMP,
2411 WL1271_CIPHER_SUITE_GEM,
2412 };
2413
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002414 /* The tx descriptor buffer and the TKIP space. */
2415 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2416 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002417
2418 /* unit us */
2419 /* FIXME: find a proper value */
2420 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002421 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422
2423 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002424 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002425 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002426 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002427 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002428 IEEE80211_HW_CONNECTION_MONITOR |
2429 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002431 wl->hw->wiphy->cipher_suites = cipher_suites;
2432 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2433
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002434 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2435 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002436 wl->hw->wiphy->max_scan_ssids = 1;
2437 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002438 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002439
Kalle Valo12bd8942010-03-18 12:26:33 +02002440 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002441 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002442
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002443 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444
2445 return 0;
2446}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002447EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002450
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002451struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002452{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002454 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002456 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002457 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
2459 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2460 if (!hw) {
2461 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002462 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002463 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 }
2465
Julia Lawall929ebd32010-05-15 23:16:39 +02002466 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002467 if (!plat_dev) {
2468 wl1271_error("could not allocate platform_device");
2469 ret = -ENOMEM;
2470 goto err_plat_alloc;
2471 }
2472
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473 wl = hw->priv;
2474 memset(wl, 0, sizeof(*wl));
2475
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002476 INIT_LIST_HEAD(&wl->list);
2477
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002479 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480
2481 skb_queue_head_init(&wl->tx_queue);
2482
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002483 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002484 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002485 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2486 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2487 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2488 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002489 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002490 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492 wl->rx_counter = 0;
2493 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2494 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002495 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002497 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002498 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002499 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2500 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002501 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002502 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002503 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002504 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002505 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002507 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508 wl->tx_frames[i] = NULL;
2509
2510 spin_lock_init(&wl->wl_lock);
2511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512 wl->state = WL1271_STATE_OFF;
2513 mutex_init(&wl->mutex);
2514
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002515 /* Apply default driver configuration. */
2516 wl1271_conf_init(wl);
2517
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002518 wl1271_debugfs_init(wl);
2519
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002520 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2521 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2522 if (!wl->aggr_buf) {
2523 ret = -ENOMEM;
2524 goto err_hw;
2525 }
2526
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002527 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002528 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002529 if (ret) {
2530 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002531 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002532 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002533 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002534
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002535 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002536 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002537 if (ret < 0) {
2538 wl1271_error("failed to create sysfs file bt_coex_state");
2539 goto err_platform;
2540 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002541
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002542 /* Create sysfs file to get HW PG version */
2543 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2544 if (ret < 0) {
2545 wl1271_error("failed to create sysfs file hw_pg_ver");
2546 goto err_bt_coex_state;
2547 }
2548
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002549 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002550
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002551err_bt_coex_state:
2552 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2553
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002554err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002555 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002556
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002557err_aggr:
2558 free_pages((unsigned long)wl->aggr_buf, order);
2559
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002560err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002561 wl1271_debugfs_exit(wl);
2562 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002563
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002564err_plat_alloc:
2565 ieee80211_free_hw(hw);
2566
2567err_hw_alloc:
2568
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002569 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002570}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002571EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002572
2573int wl1271_free_hw(struct wl1271 *wl)
2574{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002575 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002576 free_pages((unsigned long)wl->aggr_buf,
2577 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002578 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002579
2580 wl1271_debugfs_exit(wl);
2581
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002582 vfree(wl->fw);
2583 wl->fw = NULL;
2584 kfree(wl->nvs);
2585 wl->nvs = NULL;
2586
2587 kfree(wl->fw_status);
2588 kfree(wl->tx_res_if);
2589
2590 ieee80211_free_hw(wl->hw);
2591
2592 return 0;
2593}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002594EXPORT_SYMBOL_GPL(wl1271_free_hw);
2595
2596MODULE_LICENSE("GPL");
2597MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2598MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");