blob: 0fd472597fa60d270e96e9adfe1e59f8ce52de95 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200217 .psm_entry_retries = 5,
218 .psm_entry_nullfunc_retries = 3,
219 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300220 .keep_alive_interval = 55000,
221 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200223 .itrim = {
224 .enable = false,
225 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200226 },
227 .pm_config = {
228 .host_clk_settling_time = 5000,
229 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 },
231 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300232 .trigger_pacing = 1,
233 .avg_weight_rssi_beacon = 20,
234 .avg_weight_rssi_data = 10,
235 .avg_weight_snr_beacon = 20,
236 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200237 },
238 .scan = {
239 .min_dwell_time_active = 7500,
240 .max_dwell_time_active = 30000,
241 .min_dwell_time_passive = 30000,
242 .max_dwell_time_passive = 60000,
243 .num_probe_reqs = 2,
244 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200245 .rf = {
246 .tx_per_channel_power_compensation_2 = {
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 },
249 .tx_per_channel_power_compensation_5 = {
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 },
254 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255};
256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200257static void __wl1271_op_remove_interface(struct wl1271 *wl);
258
259
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200260static void wl1271_device_release(struct device *dev)
261{
262
263}
264
265static struct platform_device wl1271_device = {
266 .name = "wl1271",
267 .id = -1,
268
269 /* device model insists to have a release function */
270 .dev = {
271 .release = wl1271_device_release,
272 },
273};
274
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300275static LIST_HEAD(wl_list);
276
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300277static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
278 void *arg)
279{
280 struct net_device *dev = arg;
281 struct wireless_dev *wdev;
282 struct wiphy *wiphy;
283 struct ieee80211_hw *hw;
284 struct wl1271 *wl;
285 struct wl1271 *wl_temp;
286 int ret = 0;
287
288 /* Check that this notification is for us. */
289 if (what != NETDEV_CHANGE)
290 return NOTIFY_DONE;
291
292 wdev = dev->ieee80211_ptr;
293 if (wdev == NULL)
294 return NOTIFY_DONE;
295
296 wiphy = wdev->wiphy;
297 if (wiphy == NULL)
298 return NOTIFY_DONE;
299
300 hw = wiphy_priv(wiphy);
301 if (hw == NULL)
302 return NOTIFY_DONE;
303
304 wl_temp = hw->priv;
305 list_for_each_entry(wl, &wl_list, list) {
306 if (wl == wl_temp)
307 break;
308 }
309 if (wl != wl_temp)
310 return NOTIFY_DONE;
311
312 mutex_lock(&wl->mutex);
313
314 if (wl->state == WL1271_STATE_OFF)
315 goto out;
316
317 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
318 goto out;
319
320 ret = wl1271_ps_elp_wakeup(wl, false);
321 if (ret < 0)
322 goto out;
323
324 if ((dev->operstate == IF_OPER_UP) &&
325 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
326 wl1271_cmd_set_sta_state(wl);
327 wl1271_info("Association completed.");
328 }
329
330 wl1271_ps_elp_sleep(wl);
331
332out:
333 mutex_unlock(&wl->mutex);
334
335 return NOTIFY_OK;
336}
337
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338static void wl1271_conf_init(struct wl1271 *wl)
339{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340
341 /*
342 * This function applies the default configuration to the driver. This
343 * function is invoked upon driver load (spi probe.)
344 *
345 * The configuration is stored in a run-time structure in order to
346 * facilitate for run-time adjustment of any of the parameters. Making
347 * changes to the configuration structure will apply the new values on
348 * the next interface up (wl1271_op_start.)
349 */
350
351 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300352 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300353}
354
355
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300356static int wl1271_plt_init(struct wl1271 *wl)
357{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200358 struct conf_tx_ac_category *conf_ac;
359 struct conf_tx_tid *conf_tid;
360 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200362 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200363 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200364 return ret;
365
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200366 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200367 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200368 return ret;
369
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200370 ret = wl1271_cmd_ext_radio_parms(wl);
371 if (ret < 0)
372 return ret;
373
Luciano Coelho12419cc2010-02-18 13:25:44 +0200374 ret = wl1271_init_templates_config(wl);
375 if (ret < 0)
376 return ret;
377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 ret = wl1271_acx_init_mem_config(wl);
379 if (ret < 0)
380 return ret;
381
Luciano Coelho12419cc2010-02-18 13:25:44 +0200382 /* PHY layer config */
383 ret = wl1271_init_phy_config(wl);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 ret = wl1271_acx_dco_itrim_params(wl);
388 if (ret < 0)
389 goto out_free_memmap;
390
391 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200392 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200393 if (ret < 0)
394 goto out_free_memmap;
395
396 /* Bluetooth WLAN coexistence */
397 ret = wl1271_init_pta(wl);
398 if (ret < 0)
399 goto out_free_memmap;
400
401 /* Energy detection */
402 ret = wl1271_init_energy_detection(wl);
403 if (ret < 0)
404 goto out_free_memmap;
405
406 /* Default fragmentation threshold */
407 ret = wl1271_acx_frag_threshold(wl);
408 if (ret < 0)
409 goto out_free_memmap;
410
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200411 /* Default TID/AC configuration */
412 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200413 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200414 conf_ac = &wl->conf.tx.ac_conf[i];
415 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
416 conf_ac->cw_max, conf_ac->aifsn,
417 conf_ac->tx_op_limit);
418 if (ret < 0)
419 goto out_free_memmap;
420
Luciano Coelho12419cc2010-02-18 13:25:44 +0200421 conf_tid = &wl->conf.tx.tid_conf[i];
422 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
423 conf_tid->channel_type,
424 conf_tid->tsid,
425 conf_tid->ps_scheme,
426 conf_tid->ack_policy,
427 conf_tid->apsd_conf[0],
428 conf_tid->apsd_conf[1]);
429 if (ret < 0)
430 goto out_free_memmap;
431 }
432
Luciano Coelho12419cc2010-02-18 13:25:44 +0200433 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200434 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200436 goto out_free_memmap;
437
438 /* Configure for CAM power saving (ie. always active) */
439 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
440 if (ret < 0)
441 goto out_free_memmap;
442
443 /* configure PM */
444 ret = wl1271_acx_pm_config(wl);
445 if (ret < 0)
446 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
448 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200449
450 out_free_memmap:
451 kfree(wl->target_mem_map);
452 wl->target_mem_map = NULL;
453
454 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455}
456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457static void wl1271_fw_status(struct wl1271 *wl,
458 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200460 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 u32 total = 0;
462 int i;
463
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200464 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
467 "drv_rx_counter = %d, tx_results_counter = %d)",
468 status->intr,
469 status->fw_rx_counter,
470 status->drv_rx_counter,
471 status->tx_results_counter);
472
473 /* update number of available TX blocks */
474 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300475 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
476 wl->tx_blocks_freed[i];
477
478 wl->tx_blocks_freed[i] =
479 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl->tx_blocks_available += cnt;
481 total += cnt;
482 }
483
Ido Yariva5225502010-10-12 14:49:10 +0200484 /* if more blocks are available now, tx work can be scheduled */
485 if (total)
486 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200489 getnstimeofday(&ts);
490 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
491 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492}
493
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200494#define WL1271_IRQ_MAX_LOOPS 10
495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496static void wl1271_irq_work(struct work_struct *work)
497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300499 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200500 int loopcount = WL1271_IRQ_MAX_LOOPS;
501 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 struct wl1271 *wl =
503 container_of(work, struct wl1271, irq_work);
504
505 mutex_lock(&wl->mutex);
506
507 wl1271_debug(DEBUG_IRQ, "IRQ work");
508
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 goto out;
511
512 ret = wl1271_ps_elp_wakeup(wl, true);
513 if (ret < 0)
514 goto out;
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516 spin_lock_irqsave(&wl->wl_lock, flags);
517 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
518 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520 loopcount--;
521
522 wl1271_fw_status(wl, wl->fw_status);
523 intr = le32_to_cpu(wl->fw_status->intr);
524 if (!intr) {
525 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200526 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200527 continue;
528 }
529
530 intr &= WL1271_INTR_MASK;
531
532 if (intr & WL1271_ACX_INTR_DATA) {
533 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
534
535 /* check for tx results */
536 if (wl->fw_status->tx_results_counter !=
537 (wl->tx_results_count & 0xff))
538 wl1271_tx_complete(wl);
539
Ido Yariva5225502010-10-12 14:49:10 +0200540 /* Check if any tx blocks were freed */
541 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
542 !skb_queue_empty(&wl->tx_queue)) {
543 /*
544 * In order to avoid starvation of the TX path,
545 * call the work function directly.
546 */
547 wl1271_tx_work_locked(wl);
548 }
549
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200550 wl1271_rx(wl, wl->fw_status);
551 }
552
553 if (intr & WL1271_ACX_INTR_EVENT_A) {
554 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
555 wl1271_event_handle(wl, 0);
556 }
557
558 if (intr & WL1271_ACX_INTR_EVENT_B) {
559 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
560 wl1271_event_handle(wl, 1);
561 }
562
563 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
564 wl1271_debug(DEBUG_IRQ,
565 "WL1271_ACX_INTR_INIT_COMPLETE");
566
567 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
568 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
569
570 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300571 }
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
574 ieee80211_queue_work(wl->hw, &wl->irq_work);
575 else
576 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
577 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 wl1271_ps_elp_sleep(wl);
580
581out:
582 mutex_unlock(&wl->mutex);
583}
584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585static int wl1271_fetch_firmware(struct wl1271 *wl)
586{
587 const struct firmware *fw;
588 int ret;
589
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200590 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
592 if (ret < 0) {
593 wl1271_error("could not get firmware: %d", ret);
594 return ret;
595 }
596
597 if (fw->size % 4) {
598 wl1271_error("firmware size is not multiple of 32 bits: %zu",
599 fw->size);
600 ret = -EILSEQ;
601 goto out;
602 }
603
604 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300605 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606
607 if (!wl->fw) {
608 wl1271_error("could not allocate memory for the firmware");
609 ret = -ENOMEM;
610 goto out;
611 }
612
613 memcpy(wl->fw, fw->data, wl->fw_len);
614
615 ret = 0;
616
617out:
618 release_firmware(fw);
619
620 return ret;
621}
622
623static int wl1271_fetch_nvs(struct wl1271 *wl)
624{
625 const struct firmware *fw;
626 int ret;
627
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200628 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629
630 if (ret < 0) {
631 wl1271_error("could not get nvs file: %d", ret);
632 return ret;
633 }
634
Julia Lawall929ebd32010-05-15 23:16:39 +0200635 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 if (!wl->nvs) {
638 wl1271_error("could not allocate memory for the nvs file");
639 ret = -ENOMEM;
640 goto out;
641 }
642
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200643 wl->nvs_len = fw->size;
644
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645out:
646 release_firmware(fw);
647
648 return ret;
649}
650
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200651static void wl1271_recovery_work(struct work_struct *work)
652{
653 struct wl1271 *wl =
654 container_of(work, struct wl1271, recovery_work);
655
656 mutex_lock(&wl->mutex);
657
658 if (wl->state != WL1271_STATE_ON)
659 goto out;
660
661 wl1271_info("Hardware recovery in progress.");
662
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200663 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
664 ieee80211_connection_loss(wl->vif);
665
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200666 /* reboot the chipset */
667 __wl1271_op_remove_interface(wl);
668 ieee80211_restart_hw(wl->hw);
669
670out:
671 mutex_unlock(&wl->mutex);
672}
673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674static void wl1271_fw_wakeup(struct wl1271 *wl)
675{
676 u32 elp_reg;
677
678 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300679 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680}
681
682static int wl1271_setup(struct wl1271 *wl)
683{
684 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
685 if (!wl->fw_status)
686 return -ENOMEM;
687
688 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
689 if (!wl->tx_res_if) {
690 kfree(wl->fw_status);
691 return -ENOMEM;
692 }
693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 return 0;
695}
696
697static int wl1271_chip_wakeup(struct wl1271 *wl)
698{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300699 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 int ret = 0;
701
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200702 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200703 ret = wl1271_power_on(wl);
704 if (ret < 0)
705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200707 wl1271_io_reset(wl);
708 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
710 /* We don't need a real memory partition here, because we only want
711 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300712 memset(&partition, 0, sizeof(partition));
713 partition.reg.start = REGISTERS_BASE;
714 partition.reg.size = REGISTERS_DOWN_SIZE;
715 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716
717 /* ELP module wake up */
718 wl1271_fw_wakeup(wl);
719
720 /* whal_FwCtrl_BootSm() */
721
722 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200723 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724
725 /* 1. check if chip id is valid */
726
727 switch (wl->chip.id) {
728 case CHIP_ID_1271_PG10:
729 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
730 wl->chip.id);
731
732 ret = wl1271_setup(wl);
733 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 break;
736 case CHIP_ID_1271_PG20:
737 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
738 wl->chip.id);
739
740 ret = wl1271_setup(wl);
741 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 break;
744 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748 }
749
750 if (wl->fw == NULL) {
751 ret = wl1271_fetch_firmware(wl);
752 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200753 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 }
755
756 /* No NVS from netlink, try to get it from the filesystem */
757 if (wl->nvs == NULL) {
758 ret = wl1271_fetch_nvs(wl);
759 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200760 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761 }
762
763out:
764 return ret;
765}
766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767int wl1271_plt_start(struct wl1271 *wl)
768{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200769 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 int ret;
771
772 mutex_lock(&wl->mutex);
773
774 wl1271_notice("power up");
775
776 if (wl->state != WL1271_STATE_OFF) {
777 wl1271_error("cannot go into PLT state because not "
778 "in off state: %d", wl->state);
779 ret = -EBUSY;
780 goto out;
781 }
782
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200783 while (retries) {
784 retries--;
785 ret = wl1271_chip_wakeup(wl);
786 if (ret < 0)
787 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200789 ret = wl1271_boot(wl);
790 if (ret < 0)
791 goto power_off;
792
793 ret = wl1271_plt_init(wl);
794 if (ret < 0)
795 goto irq_disable;
796
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200797 wl->state = WL1271_STATE_PLT;
798 wl1271_notice("firmware booted in PLT mode (%s)",
799 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800 goto out;
801
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200802irq_disable:
803 wl1271_disable_interrupts(wl);
804 mutex_unlock(&wl->mutex);
805 /* Unlocking the mutex in the middle of handling is
806 inherently unsafe. In this case we deem it safe to do,
807 because we need to let any possibly pending IRQ out of
808 the system (and while we are WL1271_STATE_OFF the IRQ
809 work function will not do anything.) Also, any other
810 possible concurrent operations will fail due to the
811 current state, hence the wl1271 struct should be safe. */
812 cancel_work_sync(&wl->irq_work);
813 mutex_lock(&wl->mutex);
814power_off:
815 wl1271_power_off(wl);
816 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200818 wl1271_error("firmware boot in PLT mode failed despite %d retries",
819 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820out:
821 mutex_unlock(&wl->mutex);
822
823 return ret;
824}
825
826int wl1271_plt_stop(struct wl1271 *wl)
827{
828 int ret = 0;
829
830 mutex_lock(&wl->mutex);
831
832 wl1271_notice("power down");
833
834 if (wl->state != WL1271_STATE_PLT) {
835 wl1271_error("cannot power down because not in PLT "
836 "state: %d", wl->state);
837 ret = -EBUSY;
838 goto out;
839 }
840
841 wl1271_disable_interrupts(wl);
842 wl1271_power_off(wl);
843
844 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300845 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846
847out:
848 mutex_unlock(&wl->mutex);
849
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200850 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200851 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 return ret;
854}
855
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
857{
858 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200859 struct ieee80211_conf *conf = &hw->conf;
860 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
861 struct ieee80211_sta *sta = txinfo->control.sta;
862 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200864 /* peek into the rates configured in the STA entry */
865 spin_lock_irqsave(&wl->wl_lock, flags);
866 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
867 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
868 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
869 }
870 spin_unlock_irqrestore(&wl->wl_lock, flags);
871
872 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873 skb_queue_tail(&wl->tx_queue, skb);
874
875 /*
876 * The chip specific setup must run before the first TX packet -
877 * before that, the tx_work will not be initialized!
878 */
879
Ido Yariva5225502010-10-12 14:49:10 +0200880 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
881 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
883 /*
884 * The workqueue is slow to process the tx_queue and we need stop
885 * the queue here, otherwise the queue will get too long.
886 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200887 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
888 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200890 spin_lock_irqsave(&wl->wl_lock, flags);
891 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200892 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200893 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 }
895
896 return NETDEV_TX_OK;
897}
898
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300899static struct notifier_block wl1271_dev_notifier = {
900 .notifier_call = wl1271_dev_notify,
901};
902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903static int wl1271_op_start(struct ieee80211_hw *hw)
904{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200905 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
906
907 /*
908 * We have to delay the booting of the hardware because
909 * we need to know the local MAC address before downloading and
910 * initializing the firmware. The MAC address cannot be changed
911 * after boot, and without the proper MAC address, the firmware
912 * will not function properly.
913 *
914 * The MAC address is first known when the corresponding interface
915 * is added. That is where we will initialize the hardware.
916 */
917
918 return 0;
919}
920
921static void wl1271_op_stop(struct ieee80211_hw *hw)
922{
923 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
924}
925
926static int wl1271_op_add_interface(struct ieee80211_hw *hw,
927 struct ieee80211_vif *vif)
928{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400930 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200931 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 int ret = 0;
933
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200934 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
935 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
937 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200938 if (wl->vif) {
939 ret = -EBUSY;
940 goto out;
941 }
942
943 wl->vif = vif;
944
945 switch (vif->type) {
946 case NL80211_IFTYPE_STATION:
947 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200948 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200949 break;
950 case NL80211_IFTYPE_ADHOC:
951 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200952 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200953 break;
954 default:
955 ret = -EOPNOTSUPP;
956 goto out;
957 }
958
959 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960
961 if (wl->state != WL1271_STATE_OFF) {
962 wl1271_error("cannot start because not in off state: %d",
963 wl->state);
964 ret = -EBUSY;
965 goto out;
966 }
967
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200968 while (retries) {
969 retries--;
970 ret = wl1271_chip_wakeup(wl);
971 if (ret < 0)
972 goto power_off;
973
974 ret = wl1271_boot(wl);
975 if (ret < 0)
976 goto power_off;
977
978 ret = wl1271_hw_init(wl);
979 if (ret < 0)
980 goto irq_disable;
981
982 wl->state = WL1271_STATE_ON;
983 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400984
985 /* update hw/fw version info in wiphy struct */
986 wiphy->hw_version = wl->chip.id;
987 strncpy(wiphy->fw_version, wl->chip.fw_ver,
988 sizeof(wiphy->fw_version));
989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 goto out;
991
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200992irq_disable:
993 wl1271_disable_interrupts(wl);
994 mutex_unlock(&wl->mutex);
995 /* Unlocking the mutex in the middle of handling is
996 inherently unsafe. In this case we deem it safe to do,
997 because we need to let any possibly pending IRQ out of
998 the system (and while we are WL1271_STATE_OFF the IRQ
999 work function will not do anything.) Also, any other
1000 possible concurrent operations will fail due to the
1001 current state, hence the wl1271 struct should be safe. */
1002 cancel_work_sync(&wl->irq_work);
1003 mutex_lock(&wl->mutex);
1004power_off:
1005 wl1271_power_off(wl);
1006 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 wl1271_error("firmware boot failed despite %d retries",
1009 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001010out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 mutex_unlock(&wl->mutex);
1012
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001013 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001014 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 return ret;
1017}
1018
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001019static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 int i;
1022
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001023 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001025 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001027 list_del(&wl->list);
1028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 WARN_ON(wl->state != WL1271_STATE_ON);
1030
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001031 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001032 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001033 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001034
Luciano Coelho08688d62010-07-08 17:50:07 +03001035 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001036 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1037 kfree(wl->scan.scanned_ch);
1038 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001039 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
1042 wl->state = WL1271_STATE_OFF;
1043
1044 wl1271_disable_interrupts(wl);
1045
1046 mutex_unlock(&wl->mutex);
1047
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001048 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 cancel_work_sync(&wl->irq_work);
1050 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001051 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001052 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
1054 mutex_lock(&wl->mutex);
1055
1056 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001057 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 wl1271_power_off(wl);
1059
1060 memset(wl->bssid, 0, ETH_ALEN);
1061 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1062 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001064 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001065 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
1067 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001068 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1070 wl->tx_blocks_available = 0;
1071 wl->tx_results_count = 0;
1072 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001073 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001074 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 wl->time_offset = 0;
1076 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001077 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1078 wl->sta_rate_set = 0;
1079 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001080 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001081 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001082
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 for (i = 0; i < NUM_TX_QUEUES; i++)
1084 wl->tx_blocks_freed[i] = 0;
1085
1086 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001087
1088 kfree(wl->fw_status);
1089 wl->fw_status = NULL;
1090 kfree(wl->tx_res_if);
1091 wl->tx_res_if = NULL;
1092 kfree(wl->target_mem_map);
1093 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001094}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001095
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001096static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1097 struct ieee80211_vif *vif)
1098{
1099 struct wl1271 *wl = hw->priv;
1100
1101 mutex_lock(&wl->mutex);
1102 WARN_ON(wl->vif != vif);
1103 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001105
1106 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107}
1108
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001109static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1110{
1111 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1112 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1113
1114 /* combine requested filters with current filter config */
1115 filters = wl->filters | filters;
1116
1117 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1118
1119 if (filters & FIF_PROMISC_IN_BSS) {
1120 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1121 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1122 wl->rx_config |= CFG_BSSID_FILTER_EN;
1123 }
1124 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1125 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1126 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1127 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1128 }
1129 if (filters & FIF_OTHER_BSS) {
1130 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1131 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1132 }
1133 if (filters & FIF_CONTROL) {
1134 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1135 wl->rx_filter |= CFG_RX_CTL_EN;
1136 }
1137 if (filters & FIF_FCSFAIL) {
1138 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1139 wl->rx_filter |= CFG_RX_FCS_ERROR;
1140 }
1141}
1142
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001143static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001144{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001145 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001146 /* we need to use a dummy BSSID for now */
1147 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1148 0xad, 0xbe, 0xef };
1149
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001150 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1151
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001152 /* pass through frames from all BSS */
1153 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1154
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001155 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001156 if (ret < 0)
1157 goto out;
1158
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001159 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001160
1161out:
1162 return ret;
1163}
1164
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001165static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001166{
1167 int ret;
1168
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001169 /*
1170 * One of the side effects of the JOIN command is that is clears
1171 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1172 * to a WPA/WPA2 access point will therefore kill the data-path.
1173 * Currently there is no supported scenario for JOIN during
1174 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1175 * must be handled somehow.
1176 *
1177 */
1178 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1179 wl1271_info("JOIN while associated.");
1180
1181 if (set_assoc)
1182 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1183
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001184 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1185 if (ret < 0)
1186 goto out;
1187
1188 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1189
1190 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1191 goto out;
1192
1193 /*
1194 * The join command disable the keep-alive mode, shut down its process,
1195 * and also clear the template config, so we need to reset it all after
1196 * the join. The acx_aid starts the keep-alive process, and the order
1197 * of the commands below is relevant.
1198 */
1199 ret = wl1271_acx_keep_alive_mode(wl, true);
1200 if (ret < 0)
1201 goto out;
1202
1203 ret = wl1271_acx_aid(wl, wl->aid);
1204 if (ret < 0)
1205 goto out;
1206
1207 ret = wl1271_cmd_build_klv_null_data(wl);
1208 if (ret < 0)
1209 goto out;
1210
1211 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1212 ACX_KEEP_ALIVE_TPL_VALID);
1213 if (ret < 0)
1214 goto out;
1215
1216out:
1217 return ret;
1218}
1219
1220static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001221{
1222 int ret;
1223
1224 /* to stop listening to a channel, we disconnect */
1225 ret = wl1271_cmd_disconnect(wl);
1226 if (ret < 0)
1227 goto out;
1228
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001229 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001230 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001231
1232 /* stop filterting packets based on bssid */
1233 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001234
1235out:
1236 return ret;
1237}
1238
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001239static void wl1271_set_band_rate(struct wl1271 *wl)
1240{
1241 if (wl->band == IEEE80211_BAND_2GHZ)
1242 wl->basic_rate_set = wl->conf.tx.basic_rate;
1243 else
1244 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1245}
1246
1247static u32 wl1271_min_rate_get(struct wl1271 *wl)
1248{
1249 int i;
1250 u32 rate = 0;
1251
1252 if (!wl->basic_rate_set) {
1253 WARN_ON(1);
1254 wl->basic_rate_set = wl->conf.tx.basic_rate;
1255 }
1256
1257 for (i = 0; !rate; i++) {
1258 if ((wl->basic_rate_set >> i) & 0x1)
1259 rate = 1 << i;
1260 }
1261
1262 return rate;
1263}
1264
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001265static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1266{
1267 int ret;
1268
1269 if (idle) {
1270 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1271 ret = wl1271_unjoin(wl);
1272 if (ret < 0)
1273 goto out;
1274 }
1275 wl->rate_set = wl1271_min_rate_get(wl);
1276 wl->sta_rate_set = 0;
1277 ret = wl1271_acx_rate_policies(wl);
1278 if (ret < 0)
1279 goto out;
1280 ret = wl1271_acx_keep_alive_config(
1281 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1282 ACX_KEEP_ALIVE_TPL_INVALID);
1283 if (ret < 0)
1284 goto out;
1285 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1286 } else {
1287 /* increment the session counter */
1288 wl->session_counter++;
1289 if (wl->session_counter >= SESSION_COUNTER_MAX)
1290 wl->session_counter = 0;
1291 ret = wl1271_dummy_join(wl);
1292 if (ret < 0)
1293 goto out;
1294 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1295 }
1296
1297out:
1298 return ret;
1299}
1300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1302{
1303 struct wl1271 *wl = hw->priv;
1304 struct ieee80211_conf *conf = &hw->conf;
1305 int channel, ret = 0;
1306
1307 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1308
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001309 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 channel,
1311 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001312 conf->power_level,
1313 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001315 /*
1316 * mac80211 will go to idle nearly immediately after transmitting some
1317 * frames, such as the deauth. To make sure those frames reach the air,
1318 * wait here until the TX queue is fully flushed.
1319 */
1320 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1321 (conf->flags & IEEE80211_CONF_IDLE))
1322 wl1271_tx_flush(wl);
1323
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 mutex_lock(&wl->mutex);
1325
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001326 if (unlikely(wl->state == WL1271_STATE_OFF))
1327 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 ret = wl1271_ps_elp_wakeup(wl, false);
1330 if (ret < 0)
1331 goto out;
1332
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001333 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001334 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1335 ((wl->band != conf->channel->band) ||
1336 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001337 wl->band = conf->channel->band;
1338 wl->channel = channel;
1339
1340 /*
1341 * FIXME: the mac80211 should really provide a fixed rate
1342 * to use here. for now, just use the smallest possible rate
1343 * for the band as a fixed rate for association frames and
1344 * other control messages.
1345 */
1346 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1347 wl1271_set_band_rate(wl);
1348
1349 wl->basic_rate = wl1271_min_rate_get(wl);
1350 ret = wl1271_acx_rate_policies(wl);
1351 if (ret < 0)
1352 wl1271_warning("rate policy for update channel "
1353 "failed %d", ret);
1354
1355 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001356 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001357 if (ret < 0)
1358 wl1271_warning("cmd join to update channel "
1359 "failed %d", ret);
1360 }
1361 }
1362
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001363 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001364 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1365 if (ret < 0)
1366 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 }
1368
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001369 /*
1370 * if mac80211 changes the PSM mode, make sure the mode is not
1371 * incorrectly changed after the pspoll failure active window.
1372 */
1373 if (changed & IEEE80211_CONF_CHANGE_PS)
1374 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1375
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001376 if (conf->flags & IEEE80211_CONF_PS &&
1377 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1378 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379
1380 /*
1381 * We enter PSM only if we're already associated.
1382 * If we're not, we'll enter it when joining an SSID,
1383 * through the bss_info_changed() hook.
1384 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001385 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001386 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001387 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001388 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001389 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001391 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001392 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001394 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001396 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001397 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001398 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 }
1400
1401 if (conf->power_level != wl->power_level) {
1402 ret = wl1271_acx_tx_power(wl, conf->power_level);
1403 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001404 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405
1406 wl->power_level = conf->power_level;
1407 }
1408
1409out_sleep:
1410 wl1271_ps_elp_sleep(wl);
1411
1412out:
1413 mutex_unlock(&wl->mutex);
1414
1415 return ret;
1416}
1417
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001418struct wl1271_filter_params {
1419 bool enabled;
1420 int mc_list_length;
1421 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1422};
1423
Jiri Pirko22bedad32010-04-01 21:22:57 +00001424static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1425 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001426{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001427 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001428 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001429 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001430
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001431 if (unlikely(wl->state == WL1271_STATE_OFF))
1432 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001433
Juuso Oikarinen74441132009-10-13 12:47:53 +03001434 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001435 if (!fp) {
1436 wl1271_error("Out of memory setting filters.");
1437 return 0;
1438 }
1439
1440 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001441 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001442 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1443 fp->enabled = false;
1444 } else {
1445 fp->enabled = true;
1446 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001447 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001448 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001449 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001450 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001451 }
1452
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001453 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001454}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001456#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1457 FIF_ALLMULTI | \
1458 FIF_FCSFAIL | \
1459 FIF_BCN_PRBRESP_PROMISC | \
1460 FIF_CONTROL | \
1461 FIF_OTHER_BSS)
1462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1464 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001465 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001467 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001469 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470
1471 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1472
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001473 mutex_lock(&wl->mutex);
1474
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001475 *total &= WL1271_SUPPORTED_FILTERS;
1476 changed &= WL1271_SUPPORTED_FILTERS;
1477
1478 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001479 goto out;
1480
1481 ret = wl1271_ps_elp_wakeup(wl, false);
1482 if (ret < 0)
1483 goto out;
1484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001486 if (*total & FIF_ALLMULTI)
1487 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1488 else if (fp)
1489 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1490 fp->mc_list,
1491 fp->mc_list_length);
1492 if (ret < 0)
1493 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001495 /* determine, whether supported filter values have changed */
1496 if (changed == 0)
1497 goto out_sleep;
1498
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001499 /* configure filters */
1500 wl->filters = *total;
1501 wl1271_configure_filters(wl, 0);
1502
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001503 /* apply configured filters */
1504 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1505 if (ret < 0)
1506 goto out_sleep;
1507
1508out_sleep:
1509 wl1271_ps_elp_sleep(wl);
1510
1511out:
1512 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001513 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514}
1515
1516static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1517 struct ieee80211_vif *vif,
1518 struct ieee80211_sta *sta,
1519 struct ieee80211_key_conf *key_conf)
1520{
1521 struct wl1271 *wl = hw->priv;
1522 const u8 *addr;
1523 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001524 u32 tx_seq_32 = 0;
1525 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 u8 key_type;
1527
1528 static const u8 bcast_addr[ETH_ALEN] =
1529 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1530
1531 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1532
1533 addr = sta ? sta->addr : bcast_addr;
1534
1535 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1536 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1537 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001538 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 key_conf->keylen, key_conf->flags);
1540 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1541
1542 if (is_zero_ether_addr(addr)) {
1543 /* We dont support TX only encryption */
1544 ret = -EOPNOTSUPP;
1545 goto out;
1546 }
1547
1548 mutex_lock(&wl->mutex);
1549
1550 ret = wl1271_ps_elp_wakeup(wl, false);
1551 if (ret < 0)
1552 goto out_unlock;
1553
Johannes Berg97359d12010-08-10 09:46:38 +02001554 switch (key_conf->cipher) {
1555 case WLAN_CIPHER_SUITE_WEP40:
1556 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 key_type = KEY_WEP;
1558
1559 key_conf->hw_key_idx = key_conf->keyidx;
1560 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001561 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562 key_type = KEY_TKIP;
1563
1564 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001565 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1566 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001568 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 key_type = KEY_AES;
1570
1571 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001572 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1573 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001575 case WL1271_CIPHER_SUITE_GEM:
1576 key_type = KEY_GEM;
1577 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1578 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1579 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001581 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582
1583 ret = -EOPNOTSUPP;
1584 goto out_sleep;
1585 }
1586
1587 switch (cmd) {
1588 case SET_KEY:
1589 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1590 key_conf->keyidx, key_type,
1591 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001592 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593 if (ret < 0) {
1594 wl1271_error("Could not add or replace key");
1595 goto out_sleep;
1596 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001597
1598 /* the default WEP key needs to be configured at least once */
1599 if (key_type == KEY_WEP) {
1600 ret = wl1271_cmd_set_default_wep_key(wl,
1601 wl->default_key);
1602 if (ret < 0)
1603 goto out_sleep;
1604 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 break;
1606
1607 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001608 /* The wl1271 does not allow to remove unicast keys - they
1609 will be cleared automatically on next CMD_JOIN. Ignore the
1610 request silently, as we dont want the mac80211 to emit
1611 an error message. */
1612 if (!is_broadcast_ether_addr(addr))
1613 break;
1614
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1616 key_conf->keyidx, key_type,
1617 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001618 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 if (ret < 0) {
1620 wl1271_error("Could not remove key");
1621 goto out_sleep;
1622 }
1623 break;
1624
1625 default:
1626 wl1271_error("Unsupported key cmd 0x%x", cmd);
1627 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628 break;
1629 }
1630
1631out_sleep:
1632 wl1271_ps_elp_sleep(wl);
1633
1634out_unlock:
1635 mutex_unlock(&wl->mutex);
1636
1637out:
1638 return ret;
1639}
1640
1641static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001642 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001643 struct cfg80211_scan_request *req)
1644{
1645 struct wl1271 *wl = hw->priv;
1646 int ret;
1647 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001648 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649
1650 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1651
1652 if (req->n_ssids) {
1653 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001654 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655 }
1656
1657 mutex_lock(&wl->mutex);
1658
1659 ret = wl1271_ps_elp_wakeup(wl, false);
1660 if (ret < 0)
1661 goto out;
1662
Luciano Coelho5924f892010-08-04 03:46:22 +03001663 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664
1665 wl1271_ps_elp_sleep(wl);
1666
1667out:
1668 mutex_unlock(&wl->mutex);
1669
1670 return ret;
1671}
1672
1673static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1674{
1675 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001676 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677
1678 mutex_lock(&wl->mutex);
1679
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001680 if (unlikely(wl->state == WL1271_STATE_OFF))
1681 goto out;
1682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683 ret = wl1271_ps_elp_wakeup(wl, false);
1684 if (ret < 0)
1685 goto out;
1686
1687 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1688 if (ret < 0)
1689 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1690
1691 wl1271_ps_elp_sleep(wl);
1692
1693out:
1694 mutex_unlock(&wl->mutex);
1695
1696 return ret;
1697}
1698
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001699static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1700{
1701 u8 *ptr = beacon->data +
1702 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1703
1704 /* find the location of the ssid in the beacon */
1705 while (ptr < beacon->data + beacon->len) {
1706 if (ptr[0] == WLAN_EID_SSID) {
1707 wl->ssid_len = ptr[1];
1708 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1709 return;
1710 }
1711 ptr += ptr[1];
1712 }
1713 wl1271_error("ad-hoc beacon template has no SSID!\n");
1714}
1715
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001716static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1717 struct ieee80211_vif *vif,
1718 struct ieee80211_bss_conf *bss_conf,
1719 u32 changed)
1720{
1721 enum wl1271_cmd_ps_mode mode;
1722 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001723 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001724 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725 int ret;
1726
1727 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1728
1729 mutex_lock(&wl->mutex);
1730
1731 ret = wl1271_ps_elp_wakeup(wl, false);
1732 if (ret < 0)
1733 goto out;
1734
Eliad Peller9ee82d52010-09-19 18:55:09 +02001735 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001736 (wl->bss_type == BSS_TYPE_IBSS)) {
1737 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1738 bss_conf->beacon_int);
1739
1740 wl->beacon_int = bss_conf->beacon_int;
1741 do_join = true;
1742 }
1743
Eliad Peller9ee82d52010-09-19 18:55:09 +02001744 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001745 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001746 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1747
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001748 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1749
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001750 if (beacon) {
1751 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001752
1753 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001754 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1755 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001756 beacon->len, 0,
1757 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001758
1759 if (ret < 0) {
1760 dev_kfree_skb(beacon);
1761 goto out_sleep;
1762 }
1763
1764 hdr = (struct ieee80211_hdr *) beacon->data;
1765 hdr->frame_control = cpu_to_le16(
1766 IEEE80211_FTYPE_MGMT |
1767 IEEE80211_STYPE_PROBE_RESP);
1768
1769 ret = wl1271_cmd_template_set(wl,
1770 CMD_TEMPL_PROBE_RESPONSE,
1771 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001772 beacon->len, 0,
1773 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001774 dev_kfree_skb(beacon);
1775 if (ret < 0)
1776 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001777
1778 /* Need to update the SSID (for filtering etc) */
1779 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001780 }
1781 }
1782
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001783 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1784 (wl->bss_type == BSS_TYPE_IBSS)) {
1785 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1786 bss_conf->enable_beacon ? "enabled" : "disabled");
1787
1788 if (bss_conf->enable_beacon)
1789 wl->set_bss_type = BSS_TYPE_IBSS;
1790 else
1791 wl->set_bss_type = BSS_TYPE_STA_BSS;
1792 do_join = true;
1793 }
1794
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001795 if (changed & BSS_CHANGED_CQM) {
1796 bool enable = false;
1797 if (bss_conf->cqm_rssi_thold)
1798 enable = true;
1799 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1800 bss_conf->cqm_rssi_thold,
1801 bss_conf->cqm_rssi_hyst);
1802 if (ret < 0)
1803 goto out;
1804 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1805 }
1806
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001807 if ((changed & BSS_CHANGED_BSSID) &&
1808 /*
1809 * Now we know the correct bssid, so we send a new join command
1810 * and enable the BSSID filter
1811 */
1812 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001813 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001814
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001815 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001816 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001817 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001818
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001819 ret = wl1271_build_qos_null_data(wl);
1820 if (ret < 0)
1821 goto out_sleep;
1822
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001823 /* filter out all packets not from this BSSID */
1824 wl1271_configure_filters(wl, 0);
1825
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001826 /* Need to update the BSSID (for filtering etc) */
1827 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001828 }
1829
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 if (changed & BSS_CHANGED_ASSOC) {
1831 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001832 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001834 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001836 wl->ps_poll_failures = 0;
1837
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001838 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001839 * use basic rates from AP, and determine lowest rate
1840 * to use with control frames.
1841 */
1842 rates = bss_conf->basic_rates;
1843 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1844 rates);
1845 wl->basic_rate = wl1271_min_rate_get(wl);
1846 ret = wl1271_acx_rate_policies(wl);
1847 if (ret < 0)
1848 goto out_sleep;
1849
1850 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001851 * with wl1271, we don't need to update the
1852 * beacon_int and dtim_period, because the firmware
1853 * updates it by itself when the first beacon is
1854 * received after a join.
1855 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1857 if (ret < 0)
1858 goto out_sleep;
1859
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001860 /*
1861 * The SSID is intentionally set to NULL here - the
1862 * firmware will set the probe request with a
1863 * broadcast SSID regardless of what we set in the
1864 * template.
1865 */
1866 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1867 NULL, 0, wl->band);
1868
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001869 /* enable the connection monitoring feature */
1870 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 if (ret < 0)
1872 goto out_sleep;
1873
1874 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001875 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1876 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001878 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001879 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001880 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881 if (ret < 0)
1882 goto out_sleep;
1883 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001884 } else {
1885 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001886 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001887 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001888 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001889
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001890 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001891 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001892
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001893 /* revert back to minimum rates for the current band */
1894 wl1271_set_band_rate(wl);
1895 wl->basic_rate = wl1271_min_rate_get(wl);
1896 ret = wl1271_acx_rate_policies(wl);
1897 if (ret < 0)
1898 goto out_sleep;
1899
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001900 /* disable connection monitor features */
1901 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001902
1903 /* Disable the keep-alive feature */
1904 ret = wl1271_acx_keep_alive_mode(wl, false);
1905
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001906 if (ret < 0)
1907 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912 if (changed & BSS_CHANGED_ERP_SLOT) {
1913 if (bss_conf->use_short_slot)
1914 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1915 else
1916 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1917 if (ret < 0) {
1918 wl1271_warning("Set slot time failed %d", ret);
1919 goto out_sleep;
1920 }
1921 }
1922
1923 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1924 if (bss_conf->use_short_preamble)
1925 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1926 else
1927 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1928 }
1929
1930 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1931 if (bss_conf->use_cts_prot)
1932 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1933 else
1934 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1935 if (ret < 0) {
1936 wl1271_warning("Set ctsprotect failed %d", ret);
1937 goto out_sleep;
1938 }
1939 }
1940
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001941 if (changed & BSS_CHANGED_ARP_FILTER) {
1942 __be32 addr = bss_conf->arp_addr_list[0];
1943 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1944
1945 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1946 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1947 else
1948 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1949
1950 if (ret < 0)
1951 goto out_sleep;
1952 }
1953
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001954 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001955 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001956 if (ret < 0) {
1957 wl1271_warning("cmd join failed %d", ret);
1958 goto out_sleep;
1959 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001960 }
1961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962out_sleep:
1963 wl1271_ps_elp_sleep(wl);
1964
1965out:
1966 mutex_unlock(&wl->mutex);
1967}
1968
Kalle Valoc6999d82010-02-18 13:25:41 +02001969static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1970 const struct ieee80211_tx_queue_params *params)
1971{
1972 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001973 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001974 int ret;
1975
1976 mutex_lock(&wl->mutex);
1977
1978 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1979
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001980 ret = wl1271_ps_elp_wakeup(wl, false);
1981 if (ret < 0)
1982 goto out;
1983
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001984 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001985 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1986 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001987 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001988 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001989 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001990
Kalle Valo4695dc92010-03-18 12:26:38 +02001991 if (params->uapsd)
1992 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1993 else
1994 ps_scheme = CONF_PS_SCHEME_LEGACY;
1995
Kalle Valoc6999d82010-02-18 13:25:41 +02001996 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1997 CONF_CHANNEL_TYPE_EDCF,
1998 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001999 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002000 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002001 goto out_sleep;
2002
2003out_sleep:
2004 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002005
2006out:
2007 mutex_unlock(&wl->mutex);
2008
2009 return ret;
2010}
2011
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002012static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2013{
2014
2015 struct wl1271 *wl = hw->priv;
2016 u64 mactime = ULLONG_MAX;
2017 int ret;
2018
2019 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2020
2021 mutex_lock(&wl->mutex);
2022
2023 ret = wl1271_ps_elp_wakeup(wl, false);
2024 if (ret < 0)
2025 goto out;
2026
2027 ret = wl1271_acx_tsf_info(wl, &mactime);
2028 if (ret < 0)
2029 goto out_sleep;
2030
2031out_sleep:
2032 wl1271_ps_elp_sleep(wl);
2033
2034out:
2035 mutex_unlock(&wl->mutex);
2036 return mactime;
2037}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038
John W. Linvilleece550d2010-07-28 16:41:06 -04002039static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2040 struct survey_info *survey)
2041{
2042 struct wl1271 *wl = hw->priv;
2043 struct ieee80211_conf *conf = &hw->conf;
2044
2045 if (idx != 0)
2046 return -ENOENT;
2047
2048 survey->channel = conf->channel;
2049 survey->filled = SURVEY_INFO_NOISE_DBM;
2050 survey->noise = wl->noise;
2051
2052 return 0;
2053}
2054
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055/* can't be const, mac80211 writes to this */
2056static struct ieee80211_rate wl1271_rates[] = {
2057 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002058 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2059 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002061 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2062 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2064 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002065 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2066 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2068 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002069 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2070 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2072 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002073 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2074 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002076 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2077 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002079 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2080 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002082 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2083 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002084 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002085 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2086 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002088 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2089 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002090 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002091 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2092 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002093 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002094 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2095 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002096};
2097
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002098/*
2099 * Can't be const, mac80211 writes to this. The order of the channels here
2100 * is designed to improve scanning.
2101 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002103 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002104 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002105 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002106 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002107 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2108 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2109 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2110 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2111 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2112 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2113 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2114 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2115 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002116};
2117
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002118/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002119static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002120 /* MCS rates are used only with 11n */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2122 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2123 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2124 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2125 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2129
2130 11, /* CONF_HW_RXTX_RATE_54 */
2131 10, /* CONF_HW_RXTX_RATE_48 */
2132 9, /* CONF_HW_RXTX_RATE_36 */
2133 8, /* CONF_HW_RXTX_RATE_24 */
2134
2135 /* TI-specific rate */
2136 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2137
2138 7, /* CONF_HW_RXTX_RATE_18 */
2139 6, /* CONF_HW_RXTX_RATE_12 */
2140 3, /* CONF_HW_RXTX_RATE_11 */
2141 5, /* CONF_HW_RXTX_RATE_9 */
2142 4, /* CONF_HW_RXTX_RATE_6 */
2143 2, /* CONF_HW_RXTX_RATE_5_5 */
2144 1, /* CONF_HW_RXTX_RATE_2 */
2145 0 /* CONF_HW_RXTX_RATE_1 */
2146};
2147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148/* can't be const, mac80211 writes to this */
2149static struct ieee80211_supported_band wl1271_band_2ghz = {
2150 .channels = wl1271_channels,
2151 .n_channels = ARRAY_SIZE(wl1271_channels),
2152 .bitrates = wl1271_rates,
2153 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2154};
2155
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002156/* 5 GHz data rates for WL1273 */
2157static struct ieee80211_rate wl1271_rates_5ghz[] = {
2158 { .bitrate = 60,
2159 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2160 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2161 { .bitrate = 90,
2162 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2163 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2164 { .bitrate = 120,
2165 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2166 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2167 { .bitrate = 180,
2168 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2169 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2170 { .bitrate = 240,
2171 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2172 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2173 { .bitrate = 360,
2174 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2175 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2176 { .bitrate = 480,
2177 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2178 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2179 { .bitrate = 540,
2180 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2181 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2182};
2183
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002184/*
2185 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2186 * The order of the channels here is designed to improve scanning.
2187 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002188static struct ieee80211_channel wl1271_channels_5ghz[] = {
2189 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002190 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002191 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002192 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002193 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002194 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002195 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002196 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002197 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002198 { .hw_value = 184, .center_freq = 4920},
2199 { .hw_value = 189, .center_freq = 4945},
2200 { .hw_value = 9, .center_freq = 5045},
2201 { .hw_value = 36, .center_freq = 5180},
2202 { .hw_value = 46, .center_freq = 5230},
2203 { .hw_value = 64, .center_freq = 5320},
2204 { .hw_value = 116, .center_freq = 5580},
2205 { .hw_value = 136, .center_freq = 5680},
2206 { .hw_value = 192, .center_freq = 4960},
2207 { .hw_value = 11, .center_freq = 5055},
2208 { .hw_value = 38, .center_freq = 5190},
2209 { .hw_value = 48, .center_freq = 5240},
2210 { .hw_value = 100, .center_freq = 5500},
2211 { .hw_value = 120, .center_freq = 5600},
2212 { .hw_value = 140, .center_freq = 5700},
2213 { .hw_value = 185, .center_freq = 4925},
2214 { .hw_value = 196, .center_freq = 4980},
2215 { .hw_value = 12, .center_freq = 5060},
2216 { .hw_value = 40, .center_freq = 5200},
2217 { .hw_value = 52, .center_freq = 5260},
2218 { .hw_value = 104, .center_freq = 5520},
2219 { .hw_value = 124, .center_freq = 5620},
2220 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002221 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002222 { .hw_value = 187, .center_freq = 4935},
2223 { .hw_value = 7, .center_freq = 5035},
2224 { .hw_value = 16, .center_freq = 5080},
2225 { .hw_value = 42, .center_freq = 5210},
2226 { .hw_value = 56, .center_freq = 5280},
2227 { .hw_value = 108, .center_freq = 5540},
2228 { .hw_value = 128, .center_freq = 5640},
2229 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002230 { .hw_value = 165, .center_freq = 5825},
2231};
2232
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002233/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002234static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002235 /* MCS rates are used only with 11n */
2236 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2237 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2238 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2239 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2240 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2241 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2242 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2243 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2244
2245 7, /* CONF_HW_RXTX_RATE_54 */
2246 6, /* CONF_HW_RXTX_RATE_48 */
2247 5, /* CONF_HW_RXTX_RATE_36 */
2248 4, /* CONF_HW_RXTX_RATE_24 */
2249
2250 /* TI-specific rate */
2251 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2252
2253 3, /* CONF_HW_RXTX_RATE_18 */
2254 2, /* CONF_HW_RXTX_RATE_12 */
2255 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2256 1, /* CONF_HW_RXTX_RATE_9 */
2257 0, /* CONF_HW_RXTX_RATE_6 */
2258 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2259 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2260 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2261};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002262
2263static struct ieee80211_supported_band wl1271_band_5ghz = {
2264 .channels = wl1271_channels_5ghz,
2265 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2266 .bitrates = wl1271_rates_5ghz,
2267 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2268};
2269
Tobias Klausera0ea9492010-05-20 10:38:11 +02002270static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002271 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2272 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2273};
2274
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002275static const struct ieee80211_ops wl1271_ops = {
2276 .start = wl1271_op_start,
2277 .stop = wl1271_op_stop,
2278 .add_interface = wl1271_op_add_interface,
2279 .remove_interface = wl1271_op_remove_interface,
2280 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002281 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002282 .configure_filter = wl1271_op_configure_filter,
2283 .tx = wl1271_op_tx,
2284 .set_key = wl1271_op_set_key,
2285 .hw_scan = wl1271_op_hw_scan,
2286 .bss_info_changed = wl1271_op_bss_info_changed,
2287 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002288 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002289 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002290 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002291 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292};
2293
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002294
2295u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2296{
2297 u8 idx;
2298
2299 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2300
2301 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2302 wl1271_error("Illegal RX rate from HW: %d", rate);
2303 return 0;
2304 }
2305
2306 idx = wl1271_band_rate_to_idx[wl->band][rate];
2307 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2308 wl1271_error("Unsupported RX rate from HW: %d", rate);
2309 return 0;
2310 }
2311
2312 return idx;
2313}
2314
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002315static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2316 struct device_attribute *attr,
2317 char *buf)
2318{
2319 struct wl1271 *wl = dev_get_drvdata(dev);
2320 ssize_t len;
2321
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002322 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002323
2324 mutex_lock(&wl->mutex);
2325 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2326 wl->sg_enabled);
2327 mutex_unlock(&wl->mutex);
2328
2329 return len;
2330
2331}
2332
2333static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2334 struct device_attribute *attr,
2335 const char *buf, size_t count)
2336{
2337 struct wl1271 *wl = dev_get_drvdata(dev);
2338 unsigned long res;
2339 int ret;
2340
2341 ret = strict_strtoul(buf, 10, &res);
2342
2343 if (ret < 0) {
2344 wl1271_warning("incorrect value written to bt_coex_mode");
2345 return count;
2346 }
2347
2348 mutex_lock(&wl->mutex);
2349
2350 res = !!res;
2351
2352 if (res == wl->sg_enabled)
2353 goto out;
2354
2355 wl->sg_enabled = res;
2356
2357 if (wl->state == WL1271_STATE_OFF)
2358 goto out;
2359
2360 ret = wl1271_ps_elp_wakeup(wl, false);
2361 if (ret < 0)
2362 goto out;
2363
2364 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2365 wl1271_ps_elp_sleep(wl);
2366
2367 out:
2368 mutex_unlock(&wl->mutex);
2369 return count;
2370}
2371
2372static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2373 wl1271_sysfs_show_bt_coex_state,
2374 wl1271_sysfs_store_bt_coex_state);
2375
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002376static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2377 struct device_attribute *attr,
2378 char *buf)
2379{
2380 struct wl1271 *wl = dev_get_drvdata(dev);
2381 ssize_t len;
2382
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002383 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002384
2385 mutex_lock(&wl->mutex);
2386 if (wl->hw_pg_ver >= 0)
2387 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2388 else
2389 len = snprintf(buf, len, "n/a\n");
2390 mutex_unlock(&wl->mutex);
2391
2392 return len;
2393}
2394
2395static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2396 wl1271_sysfs_show_hw_pg_ver, NULL);
2397
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002398int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399{
2400 int ret;
2401
2402 if (wl->mac80211_registered)
2403 return 0;
2404
2405 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2406
2407 ret = ieee80211_register_hw(wl->hw);
2408 if (ret < 0) {
2409 wl1271_error("unable to register mac80211 hw: %d", ret);
2410 return ret;
2411 }
2412
2413 wl->mac80211_registered = true;
2414
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002415 register_netdevice_notifier(&wl1271_dev_notifier);
2416
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002417 wl1271_notice("loaded");
2418
2419 return 0;
2420}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002421EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002423void wl1271_unregister_hw(struct wl1271 *wl)
2424{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002425 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002426 ieee80211_unregister_hw(wl->hw);
2427 wl->mac80211_registered = false;
2428
2429}
2430EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2431
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002432int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002434 static const u32 cipher_suites[] = {
2435 WLAN_CIPHER_SUITE_WEP40,
2436 WLAN_CIPHER_SUITE_WEP104,
2437 WLAN_CIPHER_SUITE_TKIP,
2438 WLAN_CIPHER_SUITE_CCMP,
2439 WL1271_CIPHER_SUITE_GEM,
2440 };
2441
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002442 /* The tx descriptor buffer and the TKIP space. */
2443 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2444 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445
2446 /* unit us */
2447 /* FIXME: find a proper value */
2448 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002449 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450
2451 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002452 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002453 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002454 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002455 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002456 IEEE80211_HW_CONNECTION_MONITOR |
2457 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002459 wl->hw->wiphy->cipher_suites = cipher_suites;
2460 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2461
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002462 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2463 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 wl->hw->wiphy->max_scan_ssids = 1;
2465 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002466 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002467
Kalle Valo12bd8942010-03-18 12:26:33 +02002468 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002469 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002470
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002471 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002472
2473 return 0;
2474}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002475EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002476
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002478
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002479struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002482 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002484 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002485 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002486
2487 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2488 if (!hw) {
2489 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002490 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002491 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492 }
2493
Julia Lawall929ebd32010-05-15 23:16:39 +02002494 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002495 if (!plat_dev) {
2496 wl1271_error("could not allocate platform_device");
2497 ret = -ENOMEM;
2498 goto err_plat_alloc;
2499 }
2500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002501 wl = hw->priv;
2502 memset(wl, 0, sizeof(*wl));
2503
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002504 INIT_LIST_HEAD(&wl->list);
2505
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002507 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508
2509 skb_queue_head_init(&wl->tx_queue);
2510
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002511 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002512 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002513 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2514 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2515 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2516 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002518 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520 wl->rx_counter = 0;
2521 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2522 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002523 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002525 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002526 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002527 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2528 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002529 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002530 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002531 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002532 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002533 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002534
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002535 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002536 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 wl->tx_frames[i] = NULL;
2538
2539 spin_lock_init(&wl->wl_lock);
2540
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 wl->state = WL1271_STATE_OFF;
2542 mutex_init(&wl->mutex);
2543
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002544 /* Apply default driver configuration. */
2545 wl1271_conf_init(wl);
2546
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002547 wl1271_debugfs_init(wl);
2548
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002549 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2550 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2551 if (!wl->aggr_buf) {
2552 ret = -ENOMEM;
2553 goto err_hw;
2554 }
2555
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002556 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002557 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002558 if (ret) {
2559 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002560 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002561 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002562 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002563
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002564 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002565 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002566 if (ret < 0) {
2567 wl1271_error("failed to create sysfs file bt_coex_state");
2568 goto err_platform;
2569 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002570
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002571 /* Create sysfs file to get HW PG version */
2572 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2573 if (ret < 0) {
2574 wl1271_error("failed to create sysfs file hw_pg_ver");
2575 goto err_bt_coex_state;
2576 }
2577
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002578 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002579
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002580err_bt_coex_state:
2581 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2582
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002583err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002584 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002585
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002586err_aggr:
2587 free_pages((unsigned long)wl->aggr_buf, order);
2588
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002589err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002590 wl1271_debugfs_exit(wl);
2591 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002592
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002593err_plat_alloc:
2594 ieee80211_free_hw(hw);
2595
2596err_hw_alloc:
2597
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002598 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002599}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002600EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002601
2602int wl1271_free_hw(struct wl1271 *wl)
2603{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002604 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002605 free_pages((unsigned long)wl->aggr_buf,
2606 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002607 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002608
2609 wl1271_debugfs_exit(wl);
2610
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002611 vfree(wl->fw);
2612 wl->fw = NULL;
2613 kfree(wl->nvs);
2614 wl->nvs = NULL;
2615
2616 kfree(wl->fw_status);
2617 kfree(wl->tx_res_if);
2618
2619 ieee80211_free_hw(wl->hw);
2620
2621 return 0;
2622}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002623EXPORT_SYMBOL_GPL(wl1271_free_hw);
2624
2625MODULE_LICENSE("GPL");
2626MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2627MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");