blob: 8071da10dbc943e74ff60d718d8d4e3de315be76 [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
667 INIT_WORK(&wl->irq_work, wl1271_irq_work);
668 INIT_WORK(&wl->tx_work, wl1271_tx_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200669 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
Juuso Oikarinen78abd322010-09-21 06:23:32 +0200670 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Juuso Oikarinenc454f1d2010-08-24 06:28:03 +0300671
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 return 0;
673}
674
675static int wl1271_chip_wakeup(struct wl1271 *wl)
676{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300677 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 int ret = 0;
679
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200680 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200681 ret = wl1271_power_on(wl);
682 if (ret < 0)
683 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200685 wl1271_io_reset(wl);
686 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687
688 /* We don't need a real memory partition here, because we only want
689 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300690 memset(&partition, 0, sizeof(partition));
691 partition.reg.start = REGISTERS_BASE;
692 partition.reg.size = REGISTERS_DOWN_SIZE;
693 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694
695 /* ELP module wake up */
696 wl1271_fw_wakeup(wl);
697
698 /* whal_FwCtrl_BootSm() */
699
700 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200701 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 /* 1. check if chip id is valid */
704
705 switch (wl->chip.id) {
706 case CHIP_ID_1271_PG10:
707 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
708 wl->chip.id);
709
710 ret = wl1271_setup(wl);
711 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200712 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 break;
714 case CHIP_ID_1271_PG20:
715 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
716 wl->chip.id);
717
718 ret = wl1271_setup(wl);
719 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200720 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 break;
722 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200725 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726 }
727
728 if (wl->fw == NULL) {
729 ret = wl1271_fetch_firmware(wl);
730 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200731 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 }
733
734 /* No NVS from netlink, try to get it from the filesystem */
735 if (wl->nvs == NULL) {
736 ret = wl1271_fetch_nvs(wl);
737 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200738 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739 }
740
741out:
742 return ret;
743}
744
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745int wl1271_plt_start(struct wl1271 *wl)
746{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748 int ret;
749
750 mutex_lock(&wl->mutex);
751
752 wl1271_notice("power up");
753
754 if (wl->state != WL1271_STATE_OFF) {
755 wl1271_error("cannot go into PLT state because not "
756 "in off state: %d", wl->state);
757 ret = -EBUSY;
758 goto out;
759 }
760
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200761 while (retries) {
762 retries--;
763 ret = wl1271_chip_wakeup(wl);
764 if (ret < 0)
765 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200767 ret = wl1271_boot(wl);
768 if (ret < 0)
769 goto power_off;
770
771 ret = wl1271_plt_init(wl);
772 if (ret < 0)
773 goto irq_disable;
774
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200775 wl->state = WL1271_STATE_PLT;
776 wl1271_notice("firmware booted in PLT mode (%s)",
777 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 goto out;
779
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200780irq_disable:
781 wl1271_disable_interrupts(wl);
782 mutex_unlock(&wl->mutex);
783 /* Unlocking the mutex in the middle of handling is
784 inherently unsafe. In this case we deem it safe to do,
785 because we need to let any possibly pending IRQ out of
786 the system (and while we are WL1271_STATE_OFF the IRQ
787 work function will not do anything.) Also, any other
788 possible concurrent operations will fail due to the
789 current state, hence the wl1271 struct should be safe. */
790 cancel_work_sync(&wl->irq_work);
791 mutex_lock(&wl->mutex);
792power_off:
793 wl1271_power_off(wl);
794 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200796 wl1271_error("firmware boot in PLT mode failed despite %d retries",
797 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798out:
799 mutex_unlock(&wl->mutex);
800
801 return ret;
802}
803
804int wl1271_plt_stop(struct wl1271 *wl)
805{
806 int ret = 0;
807
808 mutex_lock(&wl->mutex);
809
810 wl1271_notice("power down");
811
812 if (wl->state != WL1271_STATE_PLT) {
813 wl1271_error("cannot power down because not in PLT "
814 "state: %d", wl->state);
815 ret = -EBUSY;
816 goto out;
817 }
818
819 wl1271_disable_interrupts(wl);
820 wl1271_power_off(wl);
821
822 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300823 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
825out:
826 mutex_unlock(&wl->mutex);
827
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200828 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200829 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200830
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831 return ret;
832}
833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
835{
836 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200837 struct ieee80211_conf *conf = &hw->conf;
838 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
839 struct ieee80211_sta *sta = txinfo->control.sta;
840 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200842 /* peek into the rates configured in the STA entry */
843 spin_lock_irqsave(&wl->wl_lock, flags);
844 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
845 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
846 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
847 }
848 spin_unlock_irqrestore(&wl->wl_lock, flags);
849
850 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851 skb_queue_tail(&wl->tx_queue, skb);
852
853 /*
854 * The chip specific setup must run before the first TX packet -
855 * before that, the tx_work will not be initialized!
856 */
857
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300858 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859
860 /*
861 * The workqueue is slow to process the tx_queue and we need stop
862 * the queue here, otherwise the queue will get too long.
863 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200864 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
865 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200867 spin_lock_irqsave(&wl->wl_lock, flags);
868 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200869 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200870 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871 }
872
873 return NETDEV_TX_OK;
874}
875
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300876static struct notifier_block wl1271_dev_notifier = {
877 .notifier_call = wl1271_dev_notify,
878};
879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880static int wl1271_op_start(struct ieee80211_hw *hw)
881{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200882 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
883
884 /*
885 * We have to delay the booting of the hardware because
886 * we need to know the local MAC address before downloading and
887 * initializing the firmware. The MAC address cannot be changed
888 * after boot, and without the proper MAC address, the firmware
889 * will not function properly.
890 *
891 * The MAC address is first known when the corresponding interface
892 * is added. That is where we will initialize the hardware.
893 */
894
895 return 0;
896}
897
898static void wl1271_op_stop(struct ieee80211_hw *hw)
899{
900 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
901}
902
903static int wl1271_op_add_interface(struct ieee80211_hw *hw,
904 struct ieee80211_vif *vif)
905{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300906 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400907 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200908 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909 int ret = 0;
910
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200911 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
912 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913
914 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200915 if (wl->vif) {
916 ret = -EBUSY;
917 goto out;
918 }
919
920 wl->vif = vif;
921
922 switch (vif->type) {
923 case NL80211_IFTYPE_STATION:
924 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200925 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200926 break;
927 case NL80211_IFTYPE_ADHOC:
928 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200929 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200930 break;
931 default:
932 ret = -EOPNOTSUPP;
933 goto out;
934 }
935
936 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
938 if (wl->state != WL1271_STATE_OFF) {
939 wl1271_error("cannot start because not in off state: %d",
940 wl->state);
941 ret = -EBUSY;
942 goto out;
943 }
944
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200945 while (retries) {
946 retries--;
947 ret = wl1271_chip_wakeup(wl);
948 if (ret < 0)
949 goto power_off;
950
951 ret = wl1271_boot(wl);
952 if (ret < 0)
953 goto power_off;
954
955 ret = wl1271_hw_init(wl);
956 if (ret < 0)
957 goto irq_disable;
958
959 wl->state = WL1271_STATE_ON;
960 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400961
962 /* update hw/fw version info in wiphy struct */
963 wiphy->hw_version = wl->chip.id;
964 strncpy(wiphy->fw_version, wl->chip.fw_ver,
965 sizeof(wiphy->fw_version));
966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967 goto out;
968
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200969irq_disable:
970 wl1271_disable_interrupts(wl);
971 mutex_unlock(&wl->mutex);
972 /* Unlocking the mutex in the middle of handling is
973 inherently unsafe. In this case we deem it safe to do,
974 because we need to let any possibly pending IRQ out of
975 the system (and while we are WL1271_STATE_OFF the IRQ
976 work function will not do anything.) Also, any other
977 possible concurrent operations will fail due to the
978 current state, hence the wl1271 struct should be safe. */
979 cancel_work_sync(&wl->irq_work);
980 mutex_lock(&wl->mutex);
981power_off:
982 wl1271_power_off(wl);
983 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200985 wl1271_error("firmware boot failed despite %d retries",
986 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300987out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 mutex_unlock(&wl->mutex);
989
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300990 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300991 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 return ret;
994}
995
Juuso Oikarinen52a2a372010-09-21 06:23:30 +0200996static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 int i;
999
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001000 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001002 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001004 list_del(&wl->list);
1005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 WARN_ON(wl->state != WL1271_STATE_ON);
1007
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001008 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001009 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001010 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001011
Luciano Coelho08688d62010-07-08 17:50:07 +03001012 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001013 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1014 kfree(wl->scan.scanned_ch);
1015 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001016 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017 }
1018
1019 wl->state = WL1271_STATE_OFF;
1020
1021 wl1271_disable_interrupts(wl);
1022
1023 mutex_unlock(&wl->mutex);
1024
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001025 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 cancel_work_sync(&wl->irq_work);
1027 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001028 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001029 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030
1031 mutex_lock(&wl->mutex);
1032
1033 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001034 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 wl1271_power_off(wl);
1036
1037 memset(wl->bssid, 0, ETH_ALEN);
1038 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1039 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001041 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001042 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001045 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1047 wl->tx_blocks_available = 0;
1048 wl->tx_results_count = 0;
1049 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001050 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001051 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 wl->time_offset = 0;
1053 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001054 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1055 wl->sta_rate_set = 0;
1056 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001057 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001058 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001059
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060 for (i = 0; i < NUM_TX_QUEUES; i++)
1061 wl->tx_blocks_freed[i] = 0;
1062
1063 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001064
1065 kfree(wl->fw_status);
1066 wl->fw_status = NULL;
1067 kfree(wl->tx_res_if);
1068 wl->tx_res_if = NULL;
1069 kfree(wl->target_mem_map);
1070 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001071}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001072
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001073static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1074 struct ieee80211_vif *vif)
1075{
1076 struct wl1271 *wl = hw->priv;
1077
1078 mutex_lock(&wl->mutex);
1079 WARN_ON(wl->vif != vif);
1080 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001082
1083 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084}
1085
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001086static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1087{
1088 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1089 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1090
1091 /* combine requested filters with current filter config */
1092 filters = wl->filters | filters;
1093
1094 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1095
1096 if (filters & FIF_PROMISC_IN_BSS) {
1097 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1098 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1099 wl->rx_config |= CFG_BSSID_FILTER_EN;
1100 }
1101 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1102 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1103 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1104 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1105 }
1106 if (filters & FIF_OTHER_BSS) {
1107 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1108 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1109 }
1110 if (filters & FIF_CONTROL) {
1111 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1112 wl->rx_filter |= CFG_RX_CTL_EN;
1113 }
1114 if (filters & FIF_FCSFAIL) {
1115 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1116 wl->rx_filter |= CFG_RX_FCS_ERROR;
1117 }
1118}
1119
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001120static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001121{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001122 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001123 /* we need to use a dummy BSSID for now */
1124 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1125 0xad, 0xbe, 0xef };
1126
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001127 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1128
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001129 /* pass through frames from all BSS */
1130 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1131
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001132 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133 if (ret < 0)
1134 goto out;
1135
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001136 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001137
1138out:
1139 return ret;
1140}
1141
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001142static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001143{
1144 int ret;
1145
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001146 /*
1147 * One of the side effects of the JOIN command is that is clears
1148 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1149 * to a WPA/WPA2 access point will therefore kill the data-path.
1150 * Currently there is no supported scenario for JOIN during
1151 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1152 * must be handled somehow.
1153 *
1154 */
1155 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1156 wl1271_info("JOIN while associated.");
1157
1158 if (set_assoc)
1159 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1160
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001161 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1162 if (ret < 0)
1163 goto out;
1164
1165 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1166
1167 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1168 goto out;
1169
1170 /*
1171 * The join command disable the keep-alive mode, shut down its process,
1172 * and also clear the template config, so we need to reset it all after
1173 * the join. The acx_aid starts the keep-alive process, and the order
1174 * of the commands below is relevant.
1175 */
1176 ret = wl1271_acx_keep_alive_mode(wl, true);
1177 if (ret < 0)
1178 goto out;
1179
1180 ret = wl1271_acx_aid(wl, wl->aid);
1181 if (ret < 0)
1182 goto out;
1183
1184 ret = wl1271_cmd_build_klv_null_data(wl);
1185 if (ret < 0)
1186 goto out;
1187
1188 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1189 ACX_KEEP_ALIVE_TPL_VALID);
1190 if (ret < 0)
1191 goto out;
1192
1193out:
1194 return ret;
1195}
1196
1197static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001198{
1199 int ret;
1200
1201 /* to stop listening to a channel, we disconnect */
1202 ret = wl1271_cmd_disconnect(wl);
1203 if (ret < 0)
1204 goto out;
1205
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001206 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001207 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001208
1209 /* stop filterting packets based on bssid */
1210 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001211
1212out:
1213 return ret;
1214}
1215
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001216static void wl1271_set_band_rate(struct wl1271 *wl)
1217{
1218 if (wl->band == IEEE80211_BAND_2GHZ)
1219 wl->basic_rate_set = wl->conf.tx.basic_rate;
1220 else
1221 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1222}
1223
1224static u32 wl1271_min_rate_get(struct wl1271 *wl)
1225{
1226 int i;
1227 u32 rate = 0;
1228
1229 if (!wl->basic_rate_set) {
1230 WARN_ON(1);
1231 wl->basic_rate_set = wl->conf.tx.basic_rate;
1232 }
1233
1234 for (i = 0; !rate; i++) {
1235 if ((wl->basic_rate_set >> i) & 0x1)
1236 rate = 1 << i;
1237 }
1238
1239 return rate;
1240}
1241
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001242static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1243{
1244 int ret;
1245
1246 if (idle) {
1247 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1248 ret = wl1271_unjoin(wl);
1249 if (ret < 0)
1250 goto out;
1251 }
1252 wl->rate_set = wl1271_min_rate_get(wl);
1253 wl->sta_rate_set = 0;
1254 ret = wl1271_acx_rate_policies(wl);
1255 if (ret < 0)
1256 goto out;
1257 ret = wl1271_acx_keep_alive_config(
1258 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1259 ACX_KEEP_ALIVE_TPL_INVALID);
1260 if (ret < 0)
1261 goto out;
1262 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1263 } else {
1264 /* increment the session counter */
1265 wl->session_counter++;
1266 if (wl->session_counter >= SESSION_COUNTER_MAX)
1267 wl->session_counter = 0;
1268 ret = wl1271_dummy_join(wl);
1269 if (ret < 0)
1270 goto out;
1271 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1272 }
1273
1274out:
1275 return ret;
1276}
1277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1279{
1280 struct wl1271 *wl = hw->priv;
1281 struct ieee80211_conf *conf = &hw->conf;
1282 int channel, ret = 0;
1283
1284 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1285
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001286 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287 channel,
1288 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001289 conf->power_level,
1290 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001292 /*
1293 * mac80211 will go to idle nearly immediately after transmitting some
1294 * frames, such as the deauth. To make sure those frames reach the air,
1295 * wait here until the TX queue is fully flushed.
1296 */
1297 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1298 (conf->flags & IEEE80211_CONF_IDLE))
1299 wl1271_tx_flush(wl);
1300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 mutex_lock(&wl->mutex);
1302
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001303 if (unlikely(wl->state == WL1271_STATE_OFF))
1304 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001305
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = wl1271_ps_elp_wakeup(wl, false);
1307 if (ret < 0)
1308 goto out;
1309
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001310 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001311 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1312 ((wl->band != conf->channel->band) ||
1313 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001314 wl->band = conf->channel->band;
1315 wl->channel = channel;
1316
1317 /*
1318 * FIXME: the mac80211 should really provide a fixed rate
1319 * to use here. for now, just use the smallest possible rate
1320 * for the band as a fixed rate for association frames and
1321 * other control messages.
1322 */
1323 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1324 wl1271_set_band_rate(wl);
1325
1326 wl->basic_rate = wl1271_min_rate_get(wl);
1327 ret = wl1271_acx_rate_policies(wl);
1328 if (ret < 0)
1329 wl1271_warning("rate policy for update channel "
1330 "failed %d", ret);
1331
1332 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001333 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001334 if (ret < 0)
1335 wl1271_warning("cmd join to update channel "
1336 "failed %d", ret);
1337 }
1338 }
1339
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001340 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001341 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1342 if (ret < 0)
1343 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344 }
1345
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001346 /*
1347 * if mac80211 changes the PSM mode, make sure the mode is not
1348 * incorrectly changed after the pspoll failure active window.
1349 */
1350 if (changed & IEEE80211_CONF_CHANGE_PS)
1351 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1352
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001353 if (conf->flags & IEEE80211_CONF_PS &&
1354 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1355 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356
1357 /*
1358 * We enter PSM only if we're already associated.
1359 * If we're not, we'll enter it when joining an SSID,
1360 * through the bss_info_changed() hook.
1361 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001362 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001363 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001364 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001365 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001366 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001368 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001369 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001371 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001373 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001374 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001375 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376 }
1377
1378 if (conf->power_level != wl->power_level) {
1379 ret = wl1271_acx_tx_power(wl, conf->power_level);
1380 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001381 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
1383 wl->power_level = conf->power_level;
1384 }
1385
1386out_sleep:
1387 wl1271_ps_elp_sleep(wl);
1388
1389out:
1390 mutex_unlock(&wl->mutex);
1391
1392 return ret;
1393}
1394
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001395struct wl1271_filter_params {
1396 bool enabled;
1397 int mc_list_length;
1398 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1399};
1400
Jiri Pirko22bedad32010-04-01 21:22:57 +00001401static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1402 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001403{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001404 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001405 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001406 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001407
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001408 if (unlikely(wl->state == WL1271_STATE_OFF))
1409 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001410
Juuso Oikarinen74441132009-10-13 12:47:53 +03001411 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001412 if (!fp) {
1413 wl1271_error("Out of memory setting filters.");
1414 return 0;
1415 }
1416
1417 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001418 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001419 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1420 fp->enabled = false;
1421 } else {
1422 fp->enabled = true;
1423 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001424 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001425 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001426 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001427 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001428 }
1429
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001430 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001431}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001433#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1434 FIF_ALLMULTI | \
1435 FIF_FCSFAIL | \
1436 FIF_BCN_PRBRESP_PROMISC | \
1437 FIF_CONTROL | \
1438 FIF_OTHER_BSS)
1439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1441 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001442 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001444 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001446 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447
1448 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1449
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001450 mutex_lock(&wl->mutex);
1451
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001452 *total &= WL1271_SUPPORTED_FILTERS;
1453 changed &= WL1271_SUPPORTED_FILTERS;
1454
1455 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001456 goto out;
1457
1458 ret = wl1271_ps_elp_wakeup(wl, false);
1459 if (ret < 0)
1460 goto out;
1461
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001463 if (*total & FIF_ALLMULTI)
1464 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1465 else if (fp)
1466 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1467 fp->mc_list,
1468 fp->mc_list_length);
1469 if (ret < 0)
1470 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001471
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001472 /* determine, whether supported filter values have changed */
1473 if (changed == 0)
1474 goto out_sleep;
1475
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001476 /* configure filters */
1477 wl->filters = *total;
1478 wl1271_configure_filters(wl, 0);
1479
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001480 /* apply configured filters */
1481 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1482 if (ret < 0)
1483 goto out_sleep;
1484
1485out_sleep:
1486 wl1271_ps_elp_sleep(wl);
1487
1488out:
1489 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001490 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491}
1492
1493static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1494 struct ieee80211_vif *vif,
1495 struct ieee80211_sta *sta,
1496 struct ieee80211_key_conf *key_conf)
1497{
1498 struct wl1271 *wl = hw->priv;
1499 const u8 *addr;
1500 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001501 u32 tx_seq_32 = 0;
1502 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 u8 key_type;
1504
1505 static const u8 bcast_addr[ETH_ALEN] =
1506 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1507
1508 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1509
1510 addr = sta ? sta->addr : bcast_addr;
1511
1512 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1513 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1514 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001515 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 key_conf->keylen, key_conf->flags);
1517 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1518
1519 if (is_zero_ether_addr(addr)) {
1520 /* We dont support TX only encryption */
1521 ret = -EOPNOTSUPP;
1522 goto out;
1523 }
1524
1525 mutex_lock(&wl->mutex);
1526
1527 ret = wl1271_ps_elp_wakeup(wl, false);
1528 if (ret < 0)
1529 goto out_unlock;
1530
Johannes Berg97359d12010-08-10 09:46:38 +02001531 switch (key_conf->cipher) {
1532 case WLAN_CIPHER_SUITE_WEP40:
1533 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534 key_type = KEY_WEP;
1535
1536 key_conf->hw_key_idx = key_conf->keyidx;
1537 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001538 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 key_type = KEY_TKIP;
1540
1541 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001542 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1543 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001545 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546 key_type = KEY_AES;
1547
1548 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001549 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1550 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001552 case WL1271_CIPHER_SUITE_GEM:
1553 key_type = KEY_GEM;
1554 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1555 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1556 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001558 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559
1560 ret = -EOPNOTSUPP;
1561 goto out_sleep;
1562 }
1563
1564 switch (cmd) {
1565 case SET_KEY:
1566 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1567 key_conf->keyidx, key_type,
1568 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001569 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 if (ret < 0) {
1571 wl1271_error("Could not add or replace key");
1572 goto out_sleep;
1573 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001574
1575 /* the default WEP key needs to be configured at least once */
1576 if (key_type == KEY_WEP) {
1577 ret = wl1271_cmd_set_default_wep_key(wl,
1578 wl->default_key);
1579 if (ret < 0)
1580 goto out_sleep;
1581 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582 break;
1583
1584 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001585 /* The wl1271 does not allow to remove unicast keys - they
1586 will be cleared automatically on next CMD_JOIN. Ignore the
1587 request silently, as we dont want the mac80211 to emit
1588 an error message. */
1589 if (!is_broadcast_ether_addr(addr))
1590 break;
1591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1593 key_conf->keyidx, key_type,
1594 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001595 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 if (ret < 0) {
1597 wl1271_error("Could not remove key");
1598 goto out_sleep;
1599 }
1600 break;
1601
1602 default:
1603 wl1271_error("Unsupported key cmd 0x%x", cmd);
1604 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 break;
1606 }
1607
1608out_sleep:
1609 wl1271_ps_elp_sleep(wl);
1610
1611out_unlock:
1612 mutex_unlock(&wl->mutex);
1613
1614out:
1615 return ret;
1616}
1617
1618static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001619 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 struct cfg80211_scan_request *req)
1621{
1622 struct wl1271 *wl = hw->priv;
1623 int ret;
1624 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001625 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001626
1627 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1628
1629 if (req->n_ssids) {
1630 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001631 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001632 }
1633
1634 mutex_lock(&wl->mutex);
1635
1636 ret = wl1271_ps_elp_wakeup(wl, false);
1637 if (ret < 0)
1638 goto out;
1639
Luciano Coelho5924f892010-08-04 03:46:22 +03001640 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001641
1642 wl1271_ps_elp_sleep(wl);
1643
1644out:
1645 mutex_unlock(&wl->mutex);
1646
1647 return ret;
1648}
1649
1650static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1651{
1652 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001653 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654
1655 mutex_lock(&wl->mutex);
1656
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001657 if (unlikely(wl->state == WL1271_STATE_OFF))
1658 goto out;
1659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001660 ret = wl1271_ps_elp_wakeup(wl, false);
1661 if (ret < 0)
1662 goto out;
1663
1664 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1665 if (ret < 0)
1666 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1667
1668 wl1271_ps_elp_sleep(wl);
1669
1670out:
1671 mutex_unlock(&wl->mutex);
1672
1673 return ret;
1674}
1675
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001676static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1677{
1678 u8 *ptr = beacon->data +
1679 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1680
1681 /* find the location of the ssid in the beacon */
1682 while (ptr < beacon->data + beacon->len) {
1683 if (ptr[0] == WLAN_EID_SSID) {
1684 wl->ssid_len = ptr[1];
1685 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1686 return;
1687 }
1688 ptr += ptr[1];
1689 }
1690 wl1271_error("ad-hoc beacon template has no SSID!\n");
1691}
1692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1694 struct ieee80211_vif *vif,
1695 struct ieee80211_bss_conf *bss_conf,
1696 u32 changed)
1697{
1698 enum wl1271_cmd_ps_mode mode;
1699 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001700 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001701 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702 int ret;
1703
1704 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1705
1706 mutex_lock(&wl->mutex);
1707
1708 ret = wl1271_ps_elp_wakeup(wl, false);
1709 if (ret < 0)
1710 goto out;
1711
Eliad Peller9ee82d52010-09-19 18:55:09 +02001712 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001713 (wl->bss_type == BSS_TYPE_IBSS)) {
1714 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1715 bss_conf->beacon_int);
1716
1717 wl->beacon_int = bss_conf->beacon_int;
1718 do_join = true;
1719 }
1720
Eliad Peller9ee82d52010-09-19 18:55:09 +02001721 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001722 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001723 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1724
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001725 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1726
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001727 if (beacon) {
1728 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001729
1730 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001731 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1732 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001733 beacon->len, 0,
1734 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001735
1736 if (ret < 0) {
1737 dev_kfree_skb(beacon);
1738 goto out_sleep;
1739 }
1740
1741 hdr = (struct ieee80211_hdr *) beacon->data;
1742 hdr->frame_control = cpu_to_le16(
1743 IEEE80211_FTYPE_MGMT |
1744 IEEE80211_STYPE_PROBE_RESP);
1745
1746 ret = wl1271_cmd_template_set(wl,
1747 CMD_TEMPL_PROBE_RESPONSE,
1748 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001749 beacon->len, 0,
1750 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001751 dev_kfree_skb(beacon);
1752 if (ret < 0)
1753 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001754
1755 /* Need to update the SSID (for filtering etc) */
1756 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001757 }
1758 }
1759
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001760 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1761 (wl->bss_type == BSS_TYPE_IBSS)) {
1762 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1763 bss_conf->enable_beacon ? "enabled" : "disabled");
1764
1765 if (bss_conf->enable_beacon)
1766 wl->set_bss_type = BSS_TYPE_IBSS;
1767 else
1768 wl->set_bss_type = BSS_TYPE_STA_BSS;
1769 do_join = true;
1770 }
1771
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001772 if (changed & BSS_CHANGED_CQM) {
1773 bool enable = false;
1774 if (bss_conf->cqm_rssi_thold)
1775 enable = true;
1776 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1777 bss_conf->cqm_rssi_thold,
1778 bss_conf->cqm_rssi_hyst);
1779 if (ret < 0)
1780 goto out;
1781 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1782 }
1783
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001784 if ((changed & BSS_CHANGED_BSSID) &&
1785 /*
1786 * Now we know the correct bssid, so we send a new join command
1787 * and enable the BSSID filter
1788 */
1789 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001790 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001791
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001792 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001793 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001794 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001795
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001796 ret = wl1271_build_qos_null_data(wl);
1797 if (ret < 0)
1798 goto out_sleep;
1799
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001800 /* filter out all packets not from this BSSID */
1801 wl1271_configure_filters(wl, 0);
1802
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001803 /* Need to update the BSSID (for filtering etc) */
1804 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001805 }
1806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 if (changed & BSS_CHANGED_ASSOC) {
1808 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001809 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001811 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001813 wl->ps_poll_failures = 0;
1814
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001815 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001816 * use basic rates from AP, and determine lowest rate
1817 * to use with control frames.
1818 */
1819 rates = bss_conf->basic_rates;
1820 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1821 rates);
1822 wl->basic_rate = wl1271_min_rate_get(wl);
1823 ret = wl1271_acx_rate_policies(wl);
1824 if (ret < 0)
1825 goto out_sleep;
1826
1827 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001828 * with wl1271, we don't need to update the
1829 * beacon_int and dtim_period, because the firmware
1830 * updates it by itself when the first beacon is
1831 * received after a join.
1832 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1834 if (ret < 0)
1835 goto out_sleep;
1836
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001837 /*
1838 * The SSID is intentionally set to NULL here - the
1839 * firmware will set the probe request with a
1840 * broadcast SSID regardless of what we set in the
1841 * template.
1842 */
1843 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1844 NULL, 0, wl->band);
1845
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001846 /* enable the connection monitoring feature */
1847 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001848 if (ret < 0)
1849 goto out_sleep;
1850
1851 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001852 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1853 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001855 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001856 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001857 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001858 if (ret < 0)
1859 goto out_sleep;
1860 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001861 } else {
1862 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001863 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001864 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001865 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001866
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001867 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001868 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001869
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001870 /* revert back to minimum rates for the current band */
1871 wl1271_set_band_rate(wl);
1872 wl->basic_rate = wl1271_min_rate_get(wl);
1873 ret = wl1271_acx_rate_policies(wl);
1874 if (ret < 0)
1875 goto out_sleep;
1876
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001877 /* disable connection monitor features */
1878 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001879
1880 /* Disable the keep-alive feature */
1881 ret = wl1271_acx_keep_alive_mode(wl, false);
1882
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001883 if (ret < 0)
1884 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001885 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001888
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001889 if (changed & BSS_CHANGED_ERP_SLOT) {
1890 if (bss_conf->use_short_slot)
1891 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1892 else
1893 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1894 if (ret < 0) {
1895 wl1271_warning("Set slot time failed %d", ret);
1896 goto out_sleep;
1897 }
1898 }
1899
1900 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1901 if (bss_conf->use_short_preamble)
1902 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1903 else
1904 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1905 }
1906
1907 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1908 if (bss_conf->use_cts_prot)
1909 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1910 else
1911 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1912 if (ret < 0) {
1913 wl1271_warning("Set ctsprotect failed %d", ret);
1914 goto out_sleep;
1915 }
1916 }
1917
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001918 if (changed & BSS_CHANGED_ARP_FILTER) {
1919 __be32 addr = bss_conf->arp_addr_list[0];
1920 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1921
1922 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1923 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1924 else
1925 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1926
1927 if (ret < 0)
1928 goto out_sleep;
1929 }
1930
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001931 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001932 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001933 if (ret < 0) {
1934 wl1271_warning("cmd join failed %d", ret);
1935 goto out_sleep;
1936 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001937 }
1938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939out_sleep:
1940 wl1271_ps_elp_sleep(wl);
1941
1942out:
1943 mutex_unlock(&wl->mutex);
1944}
1945
Kalle Valoc6999d82010-02-18 13:25:41 +02001946static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1947 const struct ieee80211_tx_queue_params *params)
1948{
1949 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001950 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001951 int ret;
1952
1953 mutex_lock(&wl->mutex);
1954
1955 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1956
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001957 ret = wl1271_ps_elp_wakeup(wl, false);
1958 if (ret < 0)
1959 goto out;
1960
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001961 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001962 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1963 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001964 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001965 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001966 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001967
Kalle Valo4695dc92010-03-18 12:26:38 +02001968 if (params->uapsd)
1969 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1970 else
1971 ps_scheme = CONF_PS_SCHEME_LEGACY;
1972
Kalle Valoc6999d82010-02-18 13:25:41 +02001973 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1974 CONF_CHANNEL_TYPE_EDCF,
1975 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001976 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001977 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001978 goto out_sleep;
1979
1980out_sleep:
1981 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001982
1983out:
1984 mutex_unlock(&wl->mutex);
1985
1986 return ret;
1987}
1988
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001989static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1990{
1991
1992 struct wl1271 *wl = hw->priv;
1993 u64 mactime = ULLONG_MAX;
1994 int ret;
1995
1996 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1997
1998 mutex_lock(&wl->mutex);
1999
2000 ret = wl1271_ps_elp_wakeup(wl, false);
2001 if (ret < 0)
2002 goto out;
2003
2004 ret = wl1271_acx_tsf_info(wl, &mactime);
2005 if (ret < 0)
2006 goto out_sleep;
2007
2008out_sleep:
2009 wl1271_ps_elp_sleep(wl);
2010
2011out:
2012 mutex_unlock(&wl->mutex);
2013 return mactime;
2014}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015
John W. Linvilleece550d2010-07-28 16:41:06 -04002016static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2017 struct survey_info *survey)
2018{
2019 struct wl1271 *wl = hw->priv;
2020 struct ieee80211_conf *conf = &hw->conf;
2021
2022 if (idx != 0)
2023 return -ENOENT;
2024
2025 survey->channel = conf->channel;
2026 survey->filled = SURVEY_INFO_NOISE_DBM;
2027 survey->noise = wl->noise;
2028
2029 return 0;
2030}
2031
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032/* can't be const, mac80211 writes to this */
2033static struct ieee80211_rate wl1271_rates[] = {
2034 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002035 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2036 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002038 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2039 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2041 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002042 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2043 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2045 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002046 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2047 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2049 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002050 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2051 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002053 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2054 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002056 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2057 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002059 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2060 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002062 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2063 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002065 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2066 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002068 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2069 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002071 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2072 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073};
2074
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002075/*
2076 * Can't be const, mac80211 writes to this. The order of the channels here
2077 * is designed to improve scanning.
2078 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002079static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002080 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002081 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002082 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002083 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002084 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2085 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2086 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2087 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2088 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2089 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2090 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2091 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2092 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002093};
2094
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002095/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002096static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002097 /* MCS rates are used only with 11n */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2099 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2102 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2103 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2104 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2106
2107 11, /* CONF_HW_RXTX_RATE_54 */
2108 10, /* CONF_HW_RXTX_RATE_48 */
2109 9, /* CONF_HW_RXTX_RATE_36 */
2110 8, /* CONF_HW_RXTX_RATE_24 */
2111
2112 /* TI-specific rate */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2114
2115 7, /* CONF_HW_RXTX_RATE_18 */
2116 6, /* CONF_HW_RXTX_RATE_12 */
2117 3, /* CONF_HW_RXTX_RATE_11 */
2118 5, /* CONF_HW_RXTX_RATE_9 */
2119 4, /* CONF_HW_RXTX_RATE_6 */
2120 2, /* CONF_HW_RXTX_RATE_5_5 */
2121 1, /* CONF_HW_RXTX_RATE_2 */
2122 0 /* CONF_HW_RXTX_RATE_1 */
2123};
2124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125/* can't be const, mac80211 writes to this */
2126static struct ieee80211_supported_band wl1271_band_2ghz = {
2127 .channels = wl1271_channels,
2128 .n_channels = ARRAY_SIZE(wl1271_channels),
2129 .bitrates = wl1271_rates,
2130 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2131};
2132
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002133/* 5 GHz data rates for WL1273 */
2134static struct ieee80211_rate wl1271_rates_5ghz[] = {
2135 { .bitrate = 60,
2136 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2137 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2138 { .bitrate = 90,
2139 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2140 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2141 { .bitrate = 120,
2142 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2143 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2144 { .bitrate = 180,
2145 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2146 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2147 { .bitrate = 240,
2148 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2149 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2150 { .bitrate = 360,
2151 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2152 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2153 { .bitrate = 480,
2154 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2155 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2156 { .bitrate = 540,
2157 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2158 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2159};
2160
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002161/*
2162 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2163 * The order of the channels here is designed to improve scanning.
2164 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002165static struct ieee80211_channel wl1271_channels_5ghz[] = {
2166 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002167 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002168 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002169 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002170 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002171 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002172 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002173 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002174 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002175 { .hw_value = 184, .center_freq = 4920},
2176 { .hw_value = 189, .center_freq = 4945},
2177 { .hw_value = 9, .center_freq = 5045},
2178 { .hw_value = 36, .center_freq = 5180},
2179 { .hw_value = 46, .center_freq = 5230},
2180 { .hw_value = 64, .center_freq = 5320},
2181 { .hw_value = 116, .center_freq = 5580},
2182 { .hw_value = 136, .center_freq = 5680},
2183 { .hw_value = 192, .center_freq = 4960},
2184 { .hw_value = 11, .center_freq = 5055},
2185 { .hw_value = 38, .center_freq = 5190},
2186 { .hw_value = 48, .center_freq = 5240},
2187 { .hw_value = 100, .center_freq = 5500},
2188 { .hw_value = 120, .center_freq = 5600},
2189 { .hw_value = 140, .center_freq = 5700},
2190 { .hw_value = 185, .center_freq = 4925},
2191 { .hw_value = 196, .center_freq = 4980},
2192 { .hw_value = 12, .center_freq = 5060},
2193 { .hw_value = 40, .center_freq = 5200},
2194 { .hw_value = 52, .center_freq = 5260},
2195 { .hw_value = 104, .center_freq = 5520},
2196 { .hw_value = 124, .center_freq = 5620},
2197 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002198 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002199 { .hw_value = 187, .center_freq = 4935},
2200 { .hw_value = 7, .center_freq = 5035},
2201 { .hw_value = 16, .center_freq = 5080},
2202 { .hw_value = 42, .center_freq = 5210},
2203 { .hw_value = 56, .center_freq = 5280},
2204 { .hw_value = 108, .center_freq = 5540},
2205 { .hw_value = 128, .center_freq = 5640},
2206 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002207 { .hw_value = 165, .center_freq = 5825},
2208};
2209
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002210/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002211static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002212 /* MCS rates are used only with 11n */
2213 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2214 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2215 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2216 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2217 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2218 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2219 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2220 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2221
2222 7, /* CONF_HW_RXTX_RATE_54 */
2223 6, /* CONF_HW_RXTX_RATE_48 */
2224 5, /* CONF_HW_RXTX_RATE_36 */
2225 4, /* CONF_HW_RXTX_RATE_24 */
2226
2227 /* TI-specific rate */
2228 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2229
2230 3, /* CONF_HW_RXTX_RATE_18 */
2231 2, /* CONF_HW_RXTX_RATE_12 */
2232 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2233 1, /* CONF_HW_RXTX_RATE_9 */
2234 0, /* CONF_HW_RXTX_RATE_6 */
2235 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2236 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2237 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2238};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002239
2240static struct ieee80211_supported_band wl1271_band_5ghz = {
2241 .channels = wl1271_channels_5ghz,
2242 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2243 .bitrates = wl1271_rates_5ghz,
2244 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2245};
2246
Tobias Klausera0ea9492010-05-20 10:38:11 +02002247static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002248 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2249 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2250};
2251
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002252static const struct ieee80211_ops wl1271_ops = {
2253 .start = wl1271_op_start,
2254 .stop = wl1271_op_stop,
2255 .add_interface = wl1271_op_add_interface,
2256 .remove_interface = wl1271_op_remove_interface,
2257 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002258 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002259 .configure_filter = wl1271_op_configure_filter,
2260 .tx = wl1271_op_tx,
2261 .set_key = wl1271_op_set_key,
2262 .hw_scan = wl1271_op_hw_scan,
2263 .bss_info_changed = wl1271_op_bss_info_changed,
2264 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002265 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002266 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002267 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002268 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002269};
2270
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002271
2272u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2273{
2274 u8 idx;
2275
2276 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2277
2278 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2279 wl1271_error("Illegal RX rate from HW: %d", rate);
2280 return 0;
2281 }
2282
2283 idx = wl1271_band_rate_to_idx[wl->band][rate];
2284 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2285 wl1271_error("Unsupported RX rate from HW: %d", rate);
2286 return 0;
2287 }
2288
2289 return idx;
2290}
2291
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002292static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2293 struct device_attribute *attr,
2294 char *buf)
2295{
2296 struct wl1271 *wl = dev_get_drvdata(dev);
2297 ssize_t len;
2298
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002299 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002300
2301 mutex_lock(&wl->mutex);
2302 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2303 wl->sg_enabled);
2304 mutex_unlock(&wl->mutex);
2305
2306 return len;
2307
2308}
2309
2310static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2311 struct device_attribute *attr,
2312 const char *buf, size_t count)
2313{
2314 struct wl1271 *wl = dev_get_drvdata(dev);
2315 unsigned long res;
2316 int ret;
2317
2318 ret = strict_strtoul(buf, 10, &res);
2319
2320 if (ret < 0) {
2321 wl1271_warning("incorrect value written to bt_coex_mode");
2322 return count;
2323 }
2324
2325 mutex_lock(&wl->mutex);
2326
2327 res = !!res;
2328
2329 if (res == wl->sg_enabled)
2330 goto out;
2331
2332 wl->sg_enabled = res;
2333
2334 if (wl->state == WL1271_STATE_OFF)
2335 goto out;
2336
2337 ret = wl1271_ps_elp_wakeup(wl, false);
2338 if (ret < 0)
2339 goto out;
2340
2341 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2342 wl1271_ps_elp_sleep(wl);
2343
2344 out:
2345 mutex_unlock(&wl->mutex);
2346 return count;
2347}
2348
2349static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2350 wl1271_sysfs_show_bt_coex_state,
2351 wl1271_sysfs_store_bt_coex_state);
2352
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002353static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2354 struct device_attribute *attr,
2355 char *buf)
2356{
2357 struct wl1271 *wl = dev_get_drvdata(dev);
2358 ssize_t len;
2359
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002360 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002361
2362 mutex_lock(&wl->mutex);
2363 if (wl->hw_pg_ver >= 0)
2364 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2365 else
2366 len = snprintf(buf, len, "n/a\n");
2367 mutex_unlock(&wl->mutex);
2368
2369 return len;
2370}
2371
2372static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2373 wl1271_sysfs_show_hw_pg_ver, NULL);
2374
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002375int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376{
2377 int ret;
2378
2379 if (wl->mac80211_registered)
2380 return 0;
2381
2382 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2383
2384 ret = ieee80211_register_hw(wl->hw);
2385 if (ret < 0) {
2386 wl1271_error("unable to register mac80211 hw: %d", ret);
2387 return ret;
2388 }
2389
2390 wl->mac80211_registered = true;
2391
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002392 register_netdevice_notifier(&wl1271_dev_notifier);
2393
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394 wl1271_notice("loaded");
2395
2396 return 0;
2397}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002398EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002400void wl1271_unregister_hw(struct wl1271 *wl)
2401{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002402 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002403 ieee80211_unregister_hw(wl->hw);
2404 wl->mac80211_registered = false;
2405
2406}
2407EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2408
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002409int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002410{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002411 static const u32 cipher_suites[] = {
2412 WLAN_CIPHER_SUITE_WEP40,
2413 WLAN_CIPHER_SUITE_WEP104,
2414 WLAN_CIPHER_SUITE_TKIP,
2415 WLAN_CIPHER_SUITE_CCMP,
2416 WL1271_CIPHER_SUITE_GEM,
2417 };
2418
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002419 /* The tx descriptor buffer and the TKIP space. */
2420 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2421 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422
2423 /* unit us */
2424 /* FIXME: find a proper value */
2425 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002426 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427
2428 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002429 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002430 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002431 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002432 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002433 IEEE80211_HW_CONNECTION_MONITOR |
2434 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002435
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002436 wl->hw->wiphy->cipher_suites = cipher_suites;
2437 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2438
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002439 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2440 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002441 wl->hw->wiphy->max_scan_ssids = 1;
2442 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002443 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002444
Kalle Valo12bd8942010-03-18 12:26:33 +02002445 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002446 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002447
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002448 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449
2450 return 0;
2451}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002452EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002455
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002456struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002459 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002460 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002461 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002462 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463
2464 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2465 if (!hw) {
2466 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002467 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002468 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469 }
2470
Julia Lawall929ebd32010-05-15 23:16:39 +02002471 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002472 if (!plat_dev) {
2473 wl1271_error("could not allocate platform_device");
2474 ret = -ENOMEM;
2475 goto err_plat_alloc;
2476 }
2477
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478 wl = hw->priv;
2479 memset(wl, 0, sizeof(*wl));
2480
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002481 INIT_LIST_HEAD(&wl->list);
2482
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002484 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485
2486 skb_queue_head_init(&wl->tx_queue);
2487
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002488 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002489 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002491 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002493 wl->rx_counter = 0;
2494 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2495 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002496 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002497 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002498 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002499 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002500 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2501 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002502 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002503 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002504 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002505 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002506 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002508 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002509 wl->tx_frames[i] = NULL;
2510
2511 spin_lock_init(&wl->wl_lock);
2512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 wl->state = WL1271_STATE_OFF;
2514 mutex_init(&wl->mutex);
2515
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002516 /* Apply default driver configuration. */
2517 wl1271_conf_init(wl);
2518
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002519 wl1271_debugfs_init(wl);
2520
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002521 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2522 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2523 if (!wl->aggr_buf) {
2524 ret = -ENOMEM;
2525 goto err_hw;
2526 }
2527
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002528 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002529 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002530 if (ret) {
2531 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002532 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002533 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002534 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002535
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002536 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002537 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002538 if (ret < 0) {
2539 wl1271_error("failed to create sysfs file bt_coex_state");
2540 goto err_platform;
2541 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002542
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002543 /* Create sysfs file to get HW PG version */
2544 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2545 if (ret < 0) {
2546 wl1271_error("failed to create sysfs file hw_pg_ver");
2547 goto err_bt_coex_state;
2548 }
2549
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002550 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002551
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002552err_bt_coex_state:
2553 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2554
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002555err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002556 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002557
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002558err_aggr:
2559 free_pages((unsigned long)wl->aggr_buf, order);
2560
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002561err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002562 wl1271_debugfs_exit(wl);
2563 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002564
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002565err_plat_alloc:
2566 ieee80211_free_hw(hw);
2567
2568err_hw_alloc:
2569
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002570 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002571}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002572EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002573
2574int wl1271_free_hw(struct wl1271 *wl)
2575{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002576 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002577 free_pages((unsigned long)wl->aggr_buf,
2578 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002579 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002580
2581 wl1271_debugfs_exit(wl);
2582
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002583 vfree(wl->fw);
2584 wl->fw = NULL;
2585 kfree(wl->nvs);
2586 wl->nvs = NULL;
2587
2588 kfree(wl->fw_status);
2589 kfree(wl->tx_res_if);
2590
2591 ieee80211_free_hw(wl->hw);
2592
2593 return 0;
2594}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002595EXPORT_SYMBOL_GPL(wl1271_free_hw);
2596
2597MODULE_LICENSE("GPL");
2598MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2599MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");