blob: 0026e775bb0d4da1aafa84c8dbc631d21fe12dfb [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 Oikarinenc1899552010-03-26 12:53:32 +0200217 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300218 .keep_alive_interval = 55000,
219 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200221 .itrim = {
222 .enable = false,
223 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200224 },
225 .pm_config = {
226 .host_clk_settling_time = 5000,
227 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300228 },
229 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 .trigger_pacing = 1,
231 .avg_weight_rssi_beacon = 20,
232 .avg_weight_rssi_data = 10,
233 .avg_weight_snr_beacon = 20,
234 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 }
236};
237
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200238static void wl1271_device_release(struct device *dev)
239{
240
241}
242
243static struct platform_device wl1271_device = {
244 .name = "wl1271",
245 .id = -1,
246
247 /* device model insists to have a release function */
248 .dev = {
249 .release = wl1271_device_release,
250 },
251};
252
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300253static LIST_HEAD(wl_list);
254
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300255static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
256 void *arg)
257{
258 struct net_device *dev = arg;
259 struct wireless_dev *wdev;
260 struct wiphy *wiphy;
261 struct ieee80211_hw *hw;
262 struct wl1271 *wl;
263 struct wl1271 *wl_temp;
264 int ret = 0;
265
266 /* Check that this notification is for us. */
267 if (what != NETDEV_CHANGE)
268 return NOTIFY_DONE;
269
270 wdev = dev->ieee80211_ptr;
271 if (wdev == NULL)
272 return NOTIFY_DONE;
273
274 wiphy = wdev->wiphy;
275 if (wiphy == NULL)
276 return NOTIFY_DONE;
277
278 hw = wiphy_priv(wiphy);
279 if (hw == NULL)
280 return NOTIFY_DONE;
281
282 wl_temp = hw->priv;
283 list_for_each_entry(wl, &wl_list, list) {
284 if (wl == wl_temp)
285 break;
286 }
287 if (wl != wl_temp)
288 return NOTIFY_DONE;
289
290 mutex_lock(&wl->mutex);
291
292 if (wl->state == WL1271_STATE_OFF)
293 goto out;
294
295 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
296 goto out;
297
298 ret = wl1271_ps_elp_wakeup(wl, false);
299 if (ret < 0)
300 goto out;
301
302 if ((dev->operstate == IF_OPER_UP) &&
303 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
304 wl1271_cmd_set_sta_state(wl);
305 wl1271_info("Association completed.");
306 }
307
308 wl1271_ps_elp_sleep(wl);
309
310out:
311 mutex_unlock(&wl->mutex);
312
313 return NOTIFY_OK;
314}
315
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300316static void wl1271_conf_init(struct wl1271 *wl)
317{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300318
319 /*
320 * This function applies the default configuration to the driver. This
321 * function is invoked upon driver load (spi probe.)
322 *
323 * The configuration is stored in a run-time structure in order to
324 * facilitate for run-time adjustment of any of the parameters. Making
325 * changes to the configuration structure will apply the new values on
326 * the next interface up (wl1271_op_start.)
327 */
328
329 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300330 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300331}
332
333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300334static int wl1271_plt_init(struct wl1271 *wl)
335{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200336 struct conf_tx_ac_category *conf_ac;
337 struct conf_tx_tid *conf_tid;
338 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300339
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200340 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200341 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200342 return ret;
343
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200344 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200345 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200346 return ret;
347
Luciano Coelho12419cc2010-02-18 13:25:44 +0200348 ret = wl1271_init_templates_config(wl);
349 if (ret < 0)
350 return ret;
351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352 ret = wl1271_acx_init_mem_config(wl);
353 if (ret < 0)
354 return ret;
355
Luciano Coelho12419cc2010-02-18 13:25:44 +0200356 /* PHY layer config */
357 ret = wl1271_init_phy_config(wl);
358 if (ret < 0)
359 goto out_free_memmap;
360
361 ret = wl1271_acx_dco_itrim_params(wl);
362 if (ret < 0)
363 goto out_free_memmap;
364
365 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200366 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200367 if (ret < 0)
368 goto out_free_memmap;
369
370 /* Bluetooth WLAN coexistence */
371 ret = wl1271_init_pta(wl);
372 if (ret < 0)
373 goto out_free_memmap;
374
375 /* Energy detection */
376 ret = wl1271_init_energy_detection(wl);
377 if (ret < 0)
378 goto out_free_memmap;
379
380 /* Default fragmentation threshold */
381 ret = wl1271_acx_frag_threshold(wl);
382 if (ret < 0)
383 goto out_free_memmap;
384
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200385 /* Default TID/AC configuration */
386 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200387 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200388 conf_ac = &wl->conf.tx.ac_conf[i];
389 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
390 conf_ac->cw_max, conf_ac->aifsn,
391 conf_ac->tx_op_limit);
392 if (ret < 0)
393 goto out_free_memmap;
394
Luciano Coelho12419cc2010-02-18 13:25:44 +0200395 conf_tid = &wl->conf.tx.tid_conf[i];
396 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
397 conf_tid->channel_type,
398 conf_tid->tsid,
399 conf_tid->ps_scheme,
400 conf_tid->ack_policy,
401 conf_tid->apsd_conf[0],
402 conf_tid->apsd_conf[1]);
403 if (ret < 0)
404 goto out_free_memmap;
405 }
406
Luciano Coelho12419cc2010-02-18 13:25:44 +0200407 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200408 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200410 goto out_free_memmap;
411
412 /* Configure for CAM power saving (ie. always active) */
413 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
414 if (ret < 0)
415 goto out_free_memmap;
416
417 /* configure PM */
418 ret = wl1271_acx_pm_config(wl);
419 if (ret < 0)
420 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421
422 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200423
424 out_free_memmap:
425 kfree(wl->target_mem_map);
426 wl->target_mem_map = NULL;
427
428 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429}
430
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300431static void wl1271_fw_status(struct wl1271 *wl,
432 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200434 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 u32 total = 0;
436 int i;
437
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200438 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439
440 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
441 "drv_rx_counter = %d, tx_results_counter = %d)",
442 status->intr,
443 status->fw_rx_counter,
444 status->drv_rx_counter,
445 status->tx_results_counter);
446
447 /* update number of available TX blocks */
448 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300449 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
450 wl->tx_blocks_freed[i];
451
452 wl->tx_blocks_freed[i] =
453 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454 wl->tx_blocks_available += cnt;
455 total += cnt;
456 }
457
458 /* if more blocks are available now, schedule some tx work */
459 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300460 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
462 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200463 getnstimeofday(&ts);
464 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
465 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466}
467
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200468#define WL1271_IRQ_MAX_LOOPS 10
469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470static void wl1271_irq_work(struct work_struct *work)
471{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300473 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200474 int loopcount = WL1271_IRQ_MAX_LOOPS;
475 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476 struct wl1271 *wl =
477 container_of(work, struct wl1271, irq_work);
478
479 mutex_lock(&wl->mutex);
480
481 wl1271_debug(DEBUG_IRQ, "IRQ work");
482
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200483 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484 goto out;
485
486 ret = wl1271_ps_elp_wakeup(wl, true);
487 if (ret < 0)
488 goto out;
489
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200490 spin_lock_irqsave(&wl->wl_lock, flags);
491 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
492 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
493 spin_unlock_irqrestore(&wl->wl_lock, flags);
494 loopcount--;
495
496 wl1271_fw_status(wl, wl->fw_status);
497 intr = le32_to_cpu(wl->fw_status->intr);
498 if (!intr) {
499 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200500 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200501 continue;
502 }
503
504 intr &= WL1271_INTR_MASK;
505
506 if (intr & WL1271_ACX_INTR_DATA) {
507 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
508
509 /* check for tx results */
510 if (wl->fw_status->tx_results_counter !=
511 (wl->tx_results_count & 0xff))
512 wl1271_tx_complete(wl);
513
514 wl1271_rx(wl, wl->fw_status);
515 }
516
517 if (intr & WL1271_ACX_INTR_EVENT_A) {
518 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
519 wl1271_event_handle(wl, 0);
520 }
521
522 if (intr & WL1271_ACX_INTR_EVENT_B) {
523 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
524 wl1271_event_handle(wl, 1);
525 }
526
527 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
528 wl1271_debug(DEBUG_IRQ,
529 "WL1271_ACX_INTR_INIT_COMPLETE");
530
531 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
532 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
533
534 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535 }
536
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200537 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
538 ieee80211_queue_work(wl->hw, &wl->irq_work);
539 else
540 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
541 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 wl1271_ps_elp_sleep(wl);
544
545out:
546 mutex_unlock(&wl->mutex);
547}
548
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549static int wl1271_fetch_firmware(struct wl1271 *wl)
550{
551 const struct firmware *fw;
552 int ret;
553
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200554 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 if (ret < 0) {
557 wl1271_error("could not get firmware: %d", ret);
558 return ret;
559 }
560
561 if (fw->size % 4) {
562 wl1271_error("firmware size is not multiple of 32 bits: %zu",
563 fw->size);
564 ret = -EILSEQ;
565 goto out;
566 }
567
568 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300569 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570
571 if (!wl->fw) {
572 wl1271_error("could not allocate memory for the firmware");
573 ret = -ENOMEM;
574 goto out;
575 }
576
577 memcpy(wl->fw, fw->data, wl->fw_len);
578
579 ret = 0;
580
581out:
582 release_firmware(fw);
583
584 return ret;
585}
586
587static int wl1271_fetch_nvs(struct wl1271 *wl)
588{
589 const struct firmware *fw;
590 int ret;
591
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200592 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593
594 if (ret < 0) {
595 wl1271_error("could not get nvs file: %d", ret);
596 return ret;
597 }
598
Julia Lawall929ebd32010-05-15 23:16:39 +0200599 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600
601 if (!wl->nvs) {
602 wl1271_error("could not allocate memory for the nvs file");
603 ret = -ENOMEM;
604 goto out;
605 }
606
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200607 wl->nvs_len = fw->size;
608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609out:
610 release_firmware(fw);
611
612 return ret;
613}
614
615static void wl1271_fw_wakeup(struct wl1271 *wl)
616{
617 u32 elp_reg;
618
619 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300620 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621}
622
623static int wl1271_setup(struct wl1271 *wl)
624{
625 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
626 if (!wl->fw_status)
627 return -ENOMEM;
628
629 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
630 if (!wl->tx_res_if) {
631 kfree(wl->fw_status);
632 return -ENOMEM;
633 }
634
635 INIT_WORK(&wl->irq_work, wl1271_irq_work);
636 INIT_WORK(&wl->tx_work, wl1271_tx_work);
Juuso Oikarinenc454f1d2010-08-24 06:28:03 +0300637 INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 return 0;
640}
641
642static int wl1271_chip_wakeup(struct wl1271 *wl)
643{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300644 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645 int ret = 0;
646
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200647 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200648 ret = wl1271_power_on(wl);
649 if (ret < 0)
650 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200652 wl1271_io_reset(wl);
653 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654
655 /* We don't need a real memory partition here, because we only want
656 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300657 memset(&partition, 0, sizeof(partition));
658 partition.reg.start = REGISTERS_BASE;
659 partition.reg.size = REGISTERS_DOWN_SIZE;
660 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661
662 /* ELP module wake up */
663 wl1271_fw_wakeup(wl);
664
665 /* whal_FwCtrl_BootSm() */
666
667 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200668 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669
670 /* 1. check if chip id is valid */
671
672 switch (wl->chip.id) {
673 case CHIP_ID_1271_PG10:
674 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
675 wl->chip.id);
676
677 ret = wl1271_setup(wl);
678 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 break;
681 case CHIP_ID_1271_PG20:
682 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
683 wl->chip.id);
684
685 ret = wl1271_setup(wl);
686 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200687 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 break;
689 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200692 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 }
694
695 if (wl->fw == NULL) {
696 ret = wl1271_fetch_firmware(wl);
697 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200698 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 }
700
701 /* No NVS from netlink, try to get it from the filesystem */
702 if (wl->nvs == NULL) {
703 ret = wl1271_fetch_nvs(wl);
704 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 }
707
708out:
709 return ret;
710}
711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712int wl1271_plt_start(struct wl1271 *wl)
713{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 int ret;
716
717 mutex_lock(&wl->mutex);
718
719 wl1271_notice("power up");
720
721 if (wl->state != WL1271_STATE_OFF) {
722 wl1271_error("cannot go into PLT state because not "
723 "in off state: %d", wl->state);
724 ret = -EBUSY;
725 goto out;
726 }
727
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200728 while (retries) {
729 retries--;
730 ret = wl1271_chip_wakeup(wl);
731 if (ret < 0)
732 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 ret = wl1271_boot(wl);
735 if (ret < 0)
736 goto power_off;
737
738 ret = wl1271_plt_init(wl);
739 if (ret < 0)
740 goto irq_disable;
741
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 wl->state = WL1271_STATE_PLT;
743 wl1271_notice("firmware booted in PLT mode (%s)",
744 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745 goto out;
746
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747irq_disable:
748 wl1271_disable_interrupts(wl);
749 mutex_unlock(&wl->mutex);
750 /* Unlocking the mutex in the middle of handling is
751 inherently unsafe. In this case we deem it safe to do,
752 because we need to let any possibly pending IRQ out of
753 the system (and while we are WL1271_STATE_OFF the IRQ
754 work function will not do anything.) Also, any other
755 possible concurrent operations will fail due to the
756 current state, hence the wl1271 struct should be safe. */
757 cancel_work_sync(&wl->irq_work);
758 mutex_lock(&wl->mutex);
759power_off:
760 wl1271_power_off(wl);
761 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200763 wl1271_error("firmware boot in PLT mode failed despite %d retries",
764 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765out:
766 mutex_unlock(&wl->mutex);
767
768 return ret;
769}
770
771int wl1271_plt_stop(struct wl1271 *wl)
772{
773 int ret = 0;
774
775 mutex_lock(&wl->mutex);
776
777 wl1271_notice("power down");
778
779 if (wl->state != WL1271_STATE_PLT) {
780 wl1271_error("cannot power down because not in PLT "
781 "state: %d", wl->state);
782 ret = -EBUSY;
783 goto out;
784 }
785
786 wl1271_disable_interrupts(wl);
787 wl1271_power_off(wl);
788
789 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300790 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791
792out:
793 mutex_unlock(&wl->mutex);
794
795 return ret;
796}
797
798
799static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
800{
801 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200802 struct ieee80211_conf *conf = &hw->conf;
803 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
804 struct ieee80211_sta *sta = txinfo->control.sta;
805 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200807 /* peek into the rates configured in the STA entry */
808 spin_lock_irqsave(&wl->wl_lock, flags);
809 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
810 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
811 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
812 }
813 spin_unlock_irqrestore(&wl->wl_lock, flags);
814
815 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 skb_queue_tail(&wl->tx_queue, skb);
817
818 /*
819 * The chip specific setup must run before the first TX packet -
820 * before that, the tx_work will not be initialized!
821 */
822
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300823 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
825 /*
826 * The workqueue is slow to process the tx_queue and we need stop
827 * the queue here, otherwise the queue will get too long.
828 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200829 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
830 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200832 spin_lock_irqsave(&wl->wl_lock, flags);
833 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200834 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200835 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836 }
837
838 return NETDEV_TX_OK;
839}
840
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300841static struct notifier_block wl1271_dev_notifier = {
842 .notifier_call = wl1271_dev_notify,
843};
844
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845static int wl1271_op_start(struct ieee80211_hw *hw)
846{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200847 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
848
849 /*
850 * We have to delay the booting of the hardware because
851 * we need to know the local MAC address before downloading and
852 * initializing the firmware. The MAC address cannot be changed
853 * after boot, and without the proper MAC address, the firmware
854 * will not function properly.
855 *
856 * The MAC address is first known when the corresponding interface
857 * is added. That is where we will initialize the hardware.
858 */
859
860 return 0;
861}
862
863static void wl1271_op_stop(struct ieee80211_hw *hw)
864{
865 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
866}
867
868static int wl1271_op_add_interface(struct ieee80211_hw *hw,
869 struct ieee80211_vif *vif)
870{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400872 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200873 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 int ret = 0;
875
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200876 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
877 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
879 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200880 if (wl->vif) {
881 ret = -EBUSY;
882 goto out;
883 }
884
885 wl->vif = vif;
886
887 switch (vif->type) {
888 case NL80211_IFTYPE_STATION:
889 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200890 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200891 break;
892 case NL80211_IFTYPE_ADHOC:
893 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200894 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200895 break;
896 default:
897 ret = -EOPNOTSUPP;
898 goto out;
899 }
900
901 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 if (wl->state != WL1271_STATE_OFF) {
904 wl1271_error("cannot start because not in off state: %d",
905 wl->state);
906 ret = -EBUSY;
907 goto out;
908 }
909
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200910 while (retries) {
911 retries--;
912 ret = wl1271_chip_wakeup(wl);
913 if (ret < 0)
914 goto power_off;
915
916 ret = wl1271_boot(wl);
917 if (ret < 0)
918 goto power_off;
919
920 ret = wl1271_hw_init(wl);
921 if (ret < 0)
922 goto irq_disable;
923
924 wl->state = WL1271_STATE_ON;
925 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400926
927 /* update hw/fw version info in wiphy struct */
928 wiphy->hw_version = wl->chip.id;
929 strncpy(wiphy->fw_version, wl->chip.fw_ver,
930 sizeof(wiphy->fw_version));
931
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 goto out;
933
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200934irq_disable:
935 wl1271_disable_interrupts(wl);
936 mutex_unlock(&wl->mutex);
937 /* Unlocking the mutex in the middle of handling is
938 inherently unsafe. In this case we deem it safe to do,
939 because we need to let any possibly pending IRQ out of
940 the system (and while we are WL1271_STATE_OFF the IRQ
941 work function will not do anything.) Also, any other
942 possible concurrent operations will fail due to the
943 current state, hence the wl1271 struct should be safe. */
944 cancel_work_sync(&wl->irq_work);
945 mutex_lock(&wl->mutex);
946power_off:
947 wl1271_power_off(wl);
948 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200950 wl1271_error("firmware boot failed despite %d retries",
951 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300952out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 mutex_unlock(&wl->mutex);
954
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300955 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300956 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300957
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 return ret;
959}
960
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200961static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
962 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963{
964 struct wl1271 *wl = hw->priv;
965 int i;
966
Juuso Oikarinenc454f1d2010-08-24 06:28:03 +0300967 cancel_work_sync(&wl->scan_complete_work);
968
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200969 mutex_lock(&wl->mutex);
970 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200972 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300974 list_del(&wl->list);
975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 WARN_ON(wl->state != WL1271_STATE_ON);
977
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300978 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300979 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300980 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300981
Luciano Coelho08688d62010-07-08 17:50:07 +0300982 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +0300983 wl->scan.state = WL1271_SCAN_STATE_IDLE;
984 kfree(wl->scan.scanned_ch);
985 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +0300986 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987 }
988
989 wl->state = WL1271_STATE_OFF;
990
991 wl1271_disable_interrupts(wl);
992
993 mutex_unlock(&wl->mutex);
994
995 cancel_work_sync(&wl->irq_work);
996 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300997 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998
999 mutex_lock(&wl->mutex);
1000
1001 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001002 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003 wl1271_power_off(wl);
1004
1005 memset(wl->bssid, 0, ETH_ALEN);
1006 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1007 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001009 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001010 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
1012 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001013 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1015 wl->tx_blocks_available = 0;
1016 wl->tx_results_count = 0;
1017 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001018 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001019 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020 wl->time_offset = 0;
1021 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001022 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1023 wl->sta_rate_set = 0;
1024 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001025 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001026 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 for (i = 0; i < NUM_TX_QUEUES; i++)
1029 wl->tx_blocks_freed[i] = 0;
1030
1031 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001032
1033 kfree(wl->fw_status);
1034 wl->fw_status = NULL;
1035 kfree(wl->tx_res_if);
1036 wl->tx_res_if = NULL;
1037 kfree(wl->target_mem_map);
1038 wl->target_mem_map = NULL;
1039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 mutex_unlock(&wl->mutex);
1041}
1042
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001043static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1044{
1045 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1046 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1047
1048 /* combine requested filters with current filter config */
1049 filters = wl->filters | filters;
1050
1051 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1052
1053 if (filters & FIF_PROMISC_IN_BSS) {
1054 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1055 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1056 wl->rx_config |= CFG_BSSID_FILTER_EN;
1057 }
1058 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1059 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1060 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1061 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1062 }
1063 if (filters & FIF_OTHER_BSS) {
1064 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1065 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1066 }
1067 if (filters & FIF_CONTROL) {
1068 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1069 wl->rx_filter |= CFG_RX_CTL_EN;
1070 }
1071 if (filters & FIF_FCSFAIL) {
1072 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1073 wl->rx_filter |= CFG_RX_FCS_ERROR;
1074 }
1075}
1076
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001077static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001078{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001079 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001080 /* we need to use a dummy BSSID for now */
1081 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1082 0xad, 0xbe, 0xef };
1083
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001084 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1085
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001086 /* pass through frames from all BSS */
1087 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1088
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001089 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001090 if (ret < 0)
1091 goto out;
1092
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001093 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001094
1095out:
1096 return ret;
1097}
1098
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001099static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001100{
1101 int ret;
1102
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001103 /*
1104 * One of the side effects of the JOIN command is that is clears
1105 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1106 * to a WPA/WPA2 access point will therefore kill the data-path.
1107 * Currently there is no supported scenario for JOIN during
1108 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1109 * must be handled somehow.
1110 *
1111 */
1112 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1113 wl1271_info("JOIN while associated.");
1114
1115 if (set_assoc)
1116 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1117
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001118 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1119 if (ret < 0)
1120 goto out;
1121
1122 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1123
1124 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1125 goto out;
1126
1127 /*
1128 * The join command disable the keep-alive mode, shut down its process,
1129 * and also clear the template config, so we need to reset it all after
1130 * the join. The acx_aid starts the keep-alive process, and the order
1131 * of the commands below is relevant.
1132 */
1133 ret = wl1271_acx_keep_alive_mode(wl, true);
1134 if (ret < 0)
1135 goto out;
1136
1137 ret = wl1271_acx_aid(wl, wl->aid);
1138 if (ret < 0)
1139 goto out;
1140
1141 ret = wl1271_cmd_build_klv_null_data(wl);
1142 if (ret < 0)
1143 goto out;
1144
1145 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1146 ACX_KEEP_ALIVE_TPL_VALID);
1147 if (ret < 0)
1148 goto out;
1149
1150out:
1151 return ret;
1152}
1153
1154static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001155{
1156 int ret;
1157
1158 /* to stop listening to a channel, we disconnect */
1159 ret = wl1271_cmd_disconnect(wl);
1160 if (ret < 0)
1161 goto out;
1162
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001163 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001164 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001165
1166 /* stop filterting packets based on bssid */
1167 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001168
1169out:
1170 return ret;
1171}
1172
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001173static void wl1271_set_band_rate(struct wl1271 *wl)
1174{
1175 if (wl->band == IEEE80211_BAND_2GHZ)
1176 wl->basic_rate_set = wl->conf.tx.basic_rate;
1177 else
1178 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1179}
1180
1181static u32 wl1271_min_rate_get(struct wl1271 *wl)
1182{
1183 int i;
1184 u32 rate = 0;
1185
1186 if (!wl->basic_rate_set) {
1187 WARN_ON(1);
1188 wl->basic_rate_set = wl->conf.tx.basic_rate;
1189 }
1190
1191 for (i = 0; !rate; i++) {
1192 if ((wl->basic_rate_set >> i) & 0x1)
1193 rate = 1 << i;
1194 }
1195
1196 return rate;
1197}
1198
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001199static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1200{
1201 int ret;
1202
1203 if (idle) {
1204 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1205 ret = wl1271_unjoin(wl);
1206 if (ret < 0)
1207 goto out;
1208 }
1209 wl->rate_set = wl1271_min_rate_get(wl);
1210 wl->sta_rate_set = 0;
1211 ret = wl1271_acx_rate_policies(wl);
1212 if (ret < 0)
1213 goto out;
1214 ret = wl1271_acx_keep_alive_config(
1215 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1216 ACX_KEEP_ALIVE_TPL_INVALID);
1217 if (ret < 0)
1218 goto out;
1219 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1220 } else {
1221 /* increment the session counter */
1222 wl->session_counter++;
1223 if (wl->session_counter >= SESSION_COUNTER_MAX)
1224 wl->session_counter = 0;
1225 ret = wl1271_dummy_join(wl);
1226 if (ret < 0)
1227 goto out;
1228 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1229 }
1230
1231out:
1232 return ret;
1233}
1234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1236{
1237 struct wl1271 *wl = hw->priv;
1238 struct ieee80211_conf *conf = &hw->conf;
1239 int channel, ret = 0;
1240
1241 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1242
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001243 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 channel,
1245 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001246 conf->power_level,
1247 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001249 /*
1250 * mac80211 will go to idle nearly immediately after transmitting some
1251 * frames, such as the deauth. To make sure those frames reach the air,
1252 * wait here until the TX queue is fully flushed.
1253 */
1254 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1255 (conf->flags & IEEE80211_CONF_IDLE))
1256 wl1271_tx_flush(wl);
1257
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001258 mutex_lock(&wl->mutex);
1259
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001260 if (unlikely(wl->state == WL1271_STATE_OFF))
1261 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 ret = wl1271_ps_elp_wakeup(wl, false);
1264 if (ret < 0)
1265 goto out;
1266
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001267 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001268 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1269 ((wl->band != conf->channel->band) ||
1270 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001271 wl->band = conf->channel->band;
1272 wl->channel = channel;
1273
1274 /*
1275 * FIXME: the mac80211 should really provide a fixed rate
1276 * to use here. for now, just use the smallest possible rate
1277 * for the band as a fixed rate for association frames and
1278 * other control messages.
1279 */
1280 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1281 wl1271_set_band_rate(wl);
1282
1283 wl->basic_rate = wl1271_min_rate_get(wl);
1284 ret = wl1271_acx_rate_policies(wl);
1285 if (ret < 0)
1286 wl1271_warning("rate policy for update channel "
1287 "failed %d", ret);
1288
1289 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001290 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001291 if (ret < 0)
1292 wl1271_warning("cmd join to update channel "
1293 "failed %d", ret);
1294 }
1295 }
1296
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001297 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001298 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1299 if (ret < 0)
1300 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 }
1302
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001303 /*
1304 * if mac80211 changes the PSM mode, make sure the mode is not
1305 * incorrectly changed after the pspoll failure active window.
1306 */
1307 if (changed & IEEE80211_CONF_CHANGE_PS)
1308 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1309
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001310 if (conf->flags & IEEE80211_CONF_PS &&
1311 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1312 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313
1314 /*
1315 * We enter PSM only if we're already associated.
1316 * If we're not, we'll enter it when joining an SSID,
1317 * through the bss_info_changed() hook.
1318 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001319 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001320 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001321 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001322 wl->basic_rate_set, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001323 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001325 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001326 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001328 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001330 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001331 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001332 wl->basic_rate_set, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 }
1334
1335 if (conf->power_level != wl->power_level) {
1336 ret = wl1271_acx_tx_power(wl, conf->power_level);
1337 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001338 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339
1340 wl->power_level = conf->power_level;
1341 }
1342
1343out_sleep:
1344 wl1271_ps_elp_sleep(wl);
1345
1346out:
1347 mutex_unlock(&wl->mutex);
1348
1349 return ret;
1350}
1351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352struct wl1271_filter_params {
1353 bool enabled;
1354 int mc_list_length;
1355 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1356};
1357
Jiri Pirko22bedad32010-04-01 21:22:57 +00001358static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1359 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001361 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001362 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001363 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001365 if (unlikely(wl->state == WL1271_STATE_OFF))
1366 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001367
Juuso Oikarinen74441132009-10-13 12:47:53 +03001368 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001369 if (!fp) {
1370 wl1271_error("Out of memory setting filters.");
1371 return 0;
1372 }
1373
1374 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001375 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001376 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1377 fp->enabled = false;
1378 } else {
1379 fp->enabled = true;
1380 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001381 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001382 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001383 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001384 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001385 }
1386
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001387 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001388}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001390#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1391 FIF_ALLMULTI | \
1392 FIF_FCSFAIL | \
1393 FIF_BCN_PRBRESP_PROMISC | \
1394 FIF_CONTROL | \
1395 FIF_OTHER_BSS)
1396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1398 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001399 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001401 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001403 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404
1405 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1406
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001407 mutex_lock(&wl->mutex);
1408
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001409 *total &= WL1271_SUPPORTED_FILTERS;
1410 changed &= WL1271_SUPPORTED_FILTERS;
1411
1412 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001413 goto out;
1414
1415 ret = wl1271_ps_elp_wakeup(wl, false);
1416 if (ret < 0)
1417 goto out;
1418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001420 if (*total & FIF_ALLMULTI)
1421 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1422 else if (fp)
1423 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1424 fp->mc_list,
1425 fp->mc_list_length);
1426 if (ret < 0)
1427 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001429 /* determine, whether supported filter values have changed */
1430 if (changed == 0)
1431 goto out_sleep;
1432
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001433 /* configure filters */
1434 wl->filters = *total;
1435 wl1271_configure_filters(wl, 0);
1436
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001437 /* apply configured filters */
1438 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1439 if (ret < 0)
1440 goto out_sleep;
1441
1442out_sleep:
1443 wl1271_ps_elp_sleep(wl);
1444
1445out:
1446 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001447 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448}
1449
1450static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1451 struct ieee80211_vif *vif,
1452 struct ieee80211_sta *sta,
1453 struct ieee80211_key_conf *key_conf)
1454{
1455 struct wl1271 *wl = hw->priv;
1456 const u8 *addr;
1457 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001458 u32 tx_seq_32 = 0;
1459 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 u8 key_type;
1461
1462 static const u8 bcast_addr[ETH_ALEN] =
1463 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1464
1465 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1466
1467 addr = sta ? sta->addr : bcast_addr;
1468
1469 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1470 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1471 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001472 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473 key_conf->keylen, key_conf->flags);
1474 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1475
1476 if (is_zero_ether_addr(addr)) {
1477 /* We dont support TX only encryption */
1478 ret = -EOPNOTSUPP;
1479 goto out;
1480 }
1481
1482 mutex_lock(&wl->mutex);
1483
1484 ret = wl1271_ps_elp_wakeup(wl, false);
1485 if (ret < 0)
1486 goto out_unlock;
1487
Johannes Berg97359d12010-08-10 09:46:38 +02001488 switch (key_conf->cipher) {
1489 case WLAN_CIPHER_SUITE_WEP40:
1490 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491 key_type = KEY_WEP;
1492
1493 key_conf->hw_key_idx = key_conf->keyidx;
1494 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001495 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 key_type = KEY_TKIP;
1497
1498 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001499 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1500 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001502 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 key_type = KEY_AES;
1504
1505 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001506 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1507 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 break;
1509 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001510 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511
1512 ret = -EOPNOTSUPP;
1513 goto out_sleep;
1514 }
1515
1516 switch (cmd) {
1517 case SET_KEY:
1518 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1519 key_conf->keyidx, key_type,
1520 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001521 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001522 if (ret < 0) {
1523 wl1271_error("Could not add or replace key");
1524 goto out_sleep;
1525 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001526
1527 /* the default WEP key needs to be configured at least once */
1528 if (key_type == KEY_WEP) {
1529 ret = wl1271_cmd_set_default_wep_key(wl,
1530 wl->default_key);
1531 if (ret < 0)
1532 goto out_sleep;
1533 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534 break;
1535
1536 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001537 /* The wl1271 does not allow to remove unicast keys - they
1538 will be cleared automatically on next CMD_JOIN. Ignore the
1539 request silently, as we dont want the mac80211 to emit
1540 an error message. */
1541 if (!is_broadcast_ether_addr(addr))
1542 break;
1543
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1545 key_conf->keyidx, key_type,
1546 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001547 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548 if (ret < 0) {
1549 wl1271_error("Could not remove key");
1550 goto out_sleep;
1551 }
1552 break;
1553
1554 default:
1555 wl1271_error("Unsupported key cmd 0x%x", cmd);
1556 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 break;
1558 }
1559
1560out_sleep:
1561 wl1271_ps_elp_sleep(wl);
1562
1563out_unlock:
1564 mutex_unlock(&wl->mutex);
1565
1566out:
1567 return ret;
1568}
1569
1570static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001571 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001572 struct cfg80211_scan_request *req)
1573{
1574 struct wl1271 *wl = hw->priv;
1575 int ret;
1576 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001577 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578
1579 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1580
1581 if (req->n_ssids) {
1582 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001583 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584 }
1585
1586 mutex_lock(&wl->mutex);
1587
1588 ret = wl1271_ps_elp_wakeup(wl, false);
1589 if (ret < 0)
1590 goto out;
1591
Luciano Coelho5924f892010-08-04 03:46:22 +03001592 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593
1594 wl1271_ps_elp_sleep(wl);
1595
1596out:
1597 mutex_unlock(&wl->mutex);
1598
1599 return ret;
1600}
1601
1602static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1603{
1604 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001605 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606
1607 mutex_lock(&wl->mutex);
1608
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001609 if (unlikely(wl->state == WL1271_STATE_OFF))
1610 goto out;
1611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001612 ret = wl1271_ps_elp_wakeup(wl, false);
1613 if (ret < 0)
1614 goto out;
1615
1616 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1617 if (ret < 0)
1618 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1619
1620 wl1271_ps_elp_sleep(wl);
1621
1622out:
1623 mutex_unlock(&wl->mutex);
1624
1625 return ret;
1626}
1627
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001628static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1629{
1630 u8 *ptr = beacon->data +
1631 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1632
1633 /* find the location of the ssid in the beacon */
1634 while (ptr < beacon->data + beacon->len) {
1635 if (ptr[0] == WLAN_EID_SSID) {
1636 wl->ssid_len = ptr[1];
1637 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1638 return;
1639 }
1640 ptr += ptr[1];
1641 }
1642 wl1271_error("ad-hoc beacon template has no SSID!\n");
1643}
1644
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1646 struct ieee80211_vif *vif,
1647 struct ieee80211_bss_conf *bss_conf,
1648 u32 changed)
1649{
1650 enum wl1271_cmd_ps_mode mode;
1651 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001652 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001653 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 int ret;
1655
1656 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1657
1658 mutex_lock(&wl->mutex);
1659
1660 ret = wl1271_ps_elp_wakeup(wl, false);
1661 if (ret < 0)
1662 goto out;
1663
Eliad Peller9ee82d52010-09-19 18:55:09 +02001664 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001665 (wl->bss_type == BSS_TYPE_IBSS)) {
1666 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1667 bss_conf->beacon_int);
1668
1669 wl->beacon_int = bss_conf->beacon_int;
1670 do_join = true;
1671 }
1672
Eliad Peller9ee82d52010-09-19 18:55:09 +02001673 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001674 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001675 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1676
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001677 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1678
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001679 if (beacon) {
1680 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001681
1682 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1684 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001685 beacon->len, 0,
1686 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001687
1688 if (ret < 0) {
1689 dev_kfree_skb(beacon);
1690 goto out_sleep;
1691 }
1692
1693 hdr = (struct ieee80211_hdr *) beacon->data;
1694 hdr->frame_control = cpu_to_le16(
1695 IEEE80211_FTYPE_MGMT |
1696 IEEE80211_STYPE_PROBE_RESP);
1697
1698 ret = wl1271_cmd_template_set(wl,
1699 CMD_TEMPL_PROBE_RESPONSE,
1700 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001701 beacon->len, 0,
1702 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001703 dev_kfree_skb(beacon);
1704 if (ret < 0)
1705 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001706
1707 /* Need to update the SSID (for filtering etc) */
1708 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001709 }
1710 }
1711
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001712 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1713 (wl->bss_type == BSS_TYPE_IBSS)) {
1714 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1715 bss_conf->enable_beacon ? "enabled" : "disabled");
1716
1717 if (bss_conf->enable_beacon)
1718 wl->set_bss_type = BSS_TYPE_IBSS;
1719 else
1720 wl->set_bss_type = BSS_TYPE_STA_BSS;
1721 do_join = true;
1722 }
1723
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001724 if (changed & BSS_CHANGED_CQM) {
1725 bool enable = false;
1726 if (bss_conf->cqm_rssi_thold)
1727 enable = true;
1728 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1729 bss_conf->cqm_rssi_thold,
1730 bss_conf->cqm_rssi_hyst);
1731 if (ret < 0)
1732 goto out;
1733 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1734 }
1735
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001736 if ((changed & BSS_CHANGED_BSSID) &&
1737 /*
1738 * Now we know the correct bssid, so we send a new join command
1739 * and enable the BSSID filter
1740 */
1741 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001742 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001743
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001744 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001745 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001746 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001747
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001748 ret = wl1271_build_qos_null_data(wl);
1749 if (ret < 0)
1750 goto out_sleep;
1751
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001752 /* filter out all packets not from this BSSID */
1753 wl1271_configure_filters(wl, 0);
1754
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001755 /* Need to update the BSSID (for filtering etc) */
1756 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001757 }
1758
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759 if (changed & BSS_CHANGED_ASSOC) {
1760 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001761 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001763 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001765 wl->ps_poll_failures = 0;
1766
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001767 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001768 * use basic rates from AP, and determine lowest rate
1769 * to use with control frames.
1770 */
1771 rates = bss_conf->basic_rates;
1772 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1773 rates);
1774 wl->basic_rate = wl1271_min_rate_get(wl);
1775 ret = wl1271_acx_rate_policies(wl);
1776 if (ret < 0)
1777 goto out_sleep;
1778
1779 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001780 * with wl1271, we don't need to update the
1781 * beacon_int and dtim_period, because the firmware
1782 * updates it by itself when the first beacon is
1783 * received after a join.
1784 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001785 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1786 if (ret < 0)
1787 goto out_sleep;
1788
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001789 /*
1790 * The SSID is intentionally set to NULL here - the
1791 * firmware will set the probe request with a
1792 * broadcast SSID regardless of what we set in the
1793 * template.
1794 */
1795 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1796 NULL, 0, wl->band);
1797
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001798 /* enable the connection monitoring feature */
1799 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 if (ret < 0)
1801 goto out_sleep;
1802
1803 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001804 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1805 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001807 ret = wl1271_ps_set_mode(wl, mode,
1808 wl->basic_rate_set,
1809 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 if (ret < 0)
1811 goto out_sleep;
1812 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001813 } else {
1814 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001815 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001816 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001817 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001818
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001819 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001820 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001821
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001822 /* revert back to minimum rates for the current band */
1823 wl1271_set_band_rate(wl);
1824 wl->basic_rate = wl1271_min_rate_get(wl);
1825 ret = wl1271_acx_rate_policies(wl);
1826 if (ret < 0)
1827 goto out_sleep;
1828
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001829 /* disable connection monitor features */
1830 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001831
1832 /* Disable the keep-alive feature */
1833 ret = wl1271_acx_keep_alive_mode(wl, false);
1834
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001835 if (ret < 0)
1836 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001838
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 if (changed & BSS_CHANGED_ERP_SLOT) {
1842 if (bss_conf->use_short_slot)
1843 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1844 else
1845 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1846 if (ret < 0) {
1847 wl1271_warning("Set slot time failed %d", ret);
1848 goto out_sleep;
1849 }
1850 }
1851
1852 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1853 if (bss_conf->use_short_preamble)
1854 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1855 else
1856 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1857 }
1858
1859 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1860 if (bss_conf->use_cts_prot)
1861 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1862 else
1863 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1864 if (ret < 0) {
1865 wl1271_warning("Set ctsprotect failed %d", ret);
1866 goto out_sleep;
1867 }
1868 }
1869
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001870 if (changed & BSS_CHANGED_ARP_FILTER) {
1871 __be32 addr = bss_conf->arp_addr_list[0];
1872 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1873
1874 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1875 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1876 else
1877 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1878
1879 if (ret < 0)
1880 goto out_sleep;
1881 }
1882
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001883 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001884 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001885 if (ret < 0) {
1886 wl1271_warning("cmd join failed %d", ret);
1887 goto out_sleep;
1888 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001889 }
1890
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891out_sleep:
1892 wl1271_ps_elp_sleep(wl);
1893
1894out:
1895 mutex_unlock(&wl->mutex);
1896}
1897
Kalle Valoc6999d82010-02-18 13:25:41 +02001898static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1899 const struct ieee80211_tx_queue_params *params)
1900{
1901 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001902 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001903 int ret;
1904
1905 mutex_lock(&wl->mutex);
1906
1907 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1908
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001909 ret = wl1271_ps_elp_wakeup(wl, false);
1910 if (ret < 0)
1911 goto out;
1912
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001913 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001914 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1915 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001916 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001917 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001918 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001919
Kalle Valo4695dc92010-03-18 12:26:38 +02001920 if (params->uapsd)
1921 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1922 else
1923 ps_scheme = CONF_PS_SCHEME_LEGACY;
1924
Kalle Valoc6999d82010-02-18 13:25:41 +02001925 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1926 CONF_CHANNEL_TYPE_EDCF,
1927 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001928 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001929 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001930 goto out_sleep;
1931
1932out_sleep:
1933 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001934
1935out:
1936 mutex_unlock(&wl->mutex);
1937
1938 return ret;
1939}
1940
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001941static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1942{
1943
1944 struct wl1271 *wl = hw->priv;
1945 u64 mactime = ULLONG_MAX;
1946 int ret;
1947
1948 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1949
1950 mutex_lock(&wl->mutex);
1951
1952 ret = wl1271_ps_elp_wakeup(wl, false);
1953 if (ret < 0)
1954 goto out;
1955
1956 ret = wl1271_acx_tsf_info(wl, &mactime);
1957 if (ret < 0)
1958 goto out_sleep;
1959
1960out_sleep:
1961 wl1271_ps_elp_sleep(wl);
1962
1963out:
1964 mutex_unlock(&wl->mutex);
1965 return mactime;
1966}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
John W. Linvilleece550d2010-07-28 16:41:06 -04001968static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
1969 struct survey_info *survey)
1970{
1971 struct wl1271 *wl = hw->priv;
1972 struct ieee80211_conf *conf = &hw->conf;
1973
1974 if (idx != 0)
1975 return -ENOENT;
1976
1977 survey->channel = conf->channel;
1978 survey->filled = SURVEY_INFO_NOISE_DBM;
1979 survey->noise = wl->noise;
1980
1981 return 0;
1982}
1983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984/* can't be const, mac80211 writes to this */
1985static struct ieee80211_rate wl1271_rates[] = {
1986 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001987 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1988 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001990 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1991 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1993 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001994 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1995 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1997 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001998 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1999 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2001 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002002 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2003 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002005 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2006 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002008 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2009 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002011 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2012 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002014 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2015 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002017 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2018 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002020 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2021 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002023 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2024 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025};
2026
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002027/*
2028 * Can't be const, mac80211 writes to this. The order of the channels here
2029 * is designed to improve scanning.
2030 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002032 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002033 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002034 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002035 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002036 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2037 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2038 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2039 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2040 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2041 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2042 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2043 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2044 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045};
2046
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002047/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002048static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002049 /* MCS rates are used only with 11n */
2050 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2051 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2052 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2053 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2054 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2055 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2056 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2057 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2058
2059 11, /* CONF_HW_RXTX_RATE_54 */
2060 10, /* CONF_HW_RXTX_RATE_48 */
2061 9, /* CONF_HW_RXTX_RATE_36 */
2062 8, /* CONF_HW_RXTX_RATE_24 */
2063
2064 /* TI-specific rate */
2065 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2066
2067 7, /* CONF_HW_RXTX_RATE_18 */
2068 6, /* CONF_HW_RXTX_RATE_12 */
2069 3, /* CONF_HW_RXTX_RATE_11 */
2070 5, /* CONF_HW_RXTX_RATE_9 */
2071 4, /* CONF_HW_RXTX_RATE_6 */
2072 2, /* CONF_HW_RXTX_RATE_5_5 */
2073 1, /* CONF_HW_RXTX_RATE_2 */
2074 0 /* CONF_HW_RXTX_RATE_1 */
2075};
2076
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077/* can't be const, mac80211 writes to this */
2078static struct ieee80211_supported_band wl1271_band_2ghz = {
2079 .channels = wl1271_channels,
2080 .n_channels = ARRAY_SIZE(wl1271_channels),
2081 .bitrates = wl1271_rates,
2082 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2083};
2084
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002085/* 5 GHz data rates for WL1273 */
2086static struct ieee80211_rate wl1271_rates_5ghz[] = {
2087 { .bitrate = 60,
2088 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2089 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2090 { .bitrate = 90,
2091 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2092 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2093 { .bitrate = 120,
2094 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2095 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2096 { .bitrate = 180,
2097 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2098 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2099 { .bitrate = 240,
2100 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2101 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2102 { .bitrate = 360,
2103 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2104 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2105 { .bitrate = 480,
2106 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2107 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2108 { .bitrate = 540,
2109 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2110 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2111};
2112
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002113/*
2114 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2115 * The order of the channels here is designed to improve scanning.
2116 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002117static struct ieee80211_channel wl1271_channels_5ghz[] = {
2118 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002119 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002120 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002121 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002122 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002123 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002124 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002125 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002126 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002127 { .hw_value = 184, .center_freq = 4920},
2128 { .hw_value = 189, .center_freq = 4945},
2129 { .hw_value = 9, .center_freq = 5045},
2130 { .hw_value = 36, .center_freq = 5180},
2131 { .hw_value = 46, .center_freq = 5230},
2132 { .hw_value = 64, .center_freq = 5320},
2133 { .hw_value = 116, .center_freq = 5580},
2134 { .hw_value = 136, .center_freq = 5680},
2135 { .hw_value = 192, .center_freq = 4960},
2136 { .hw_value = 11, .center_freq = 5055},
2137 { .hw_value = 38, .center_freq = 5190},
2138 { .hw_value = 48, .center_freq = 5240},
2139 { .hw_value = 100, .center_freq = 5500},
2140 { .hw_value = 120, .center_freq = 5600},
2141 { .hw_value = 140, .center_freq = 5700},
2142 { .hw_value = 185, .center_freq = 4925},
2143 { .hw_value = 196, .center_freq = 4980},
2144 { .hw_value = 12, .center_freq = 5060},
2145 { .hw_value = 40, .center_freq = 5200},
2146 { .hw_value = 52, .center_freq = 5260},
2147 { .hw_value = 104, .center_freq = 5520},
2148 { .hw_value = 124, .center_freq = 5620},
2149 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002150 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002151 { .hw_value = 187, .center_freq = 4935},
2152 { .hw_value = 7, .center_freq = 5035},
2153 { .hw_value = 16, .center_freq = 5080},
2154 { .hw_value = 42, .center_freq = 5210},
2155 { .hw_value = 56, .center_freq = 5280},
2156 { .hw_value = 108, .center_freq = 5540},
2157 { .hw_value = 128, .center_freq = 5640},
2158 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002159 { .hw_value = 165, .center_freq = 5825},
2160};
2161
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002162/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002163static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002164 /* MCS rates are used only with 11n */
2165 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2166 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2167 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2168 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2169 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2170 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2171 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2172 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2173
2174 7, /* CONF_HW_RXTX_RATE_54 */
2175 6, /* CONF_HW_RXTX_RATE_48 */
2176 5, /* CONF_HW_RXTX_RATE_36 */
2177 4, /* CONF_HW_RXTX_RATE_24 */
2178
2179 /* TI-specific rate */
2180 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2181
2182 3, /* CONF_HW_RXTX_RATE_18 */
2183 2, /* CONF_HW_RXTX_RATE_12 */
2184 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2185 1, /* CONF_HW_RXTX_RATE_9 */
2186 0, /* CONF_HW_RXTX_RATE_6 */
2187 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2188 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2189 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2190};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002191
2192static struct ieee80211_supported_band wl1271_band_5ghz = {
2193 .channels = wl1271_channels_5ghz,
2194 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2195 .bitrates = wl1271_rates_5ghz,
2196 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2197};
2198
Tobias Klausera0ea9492010-05-20 10:38:11 +02002199static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002200 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2201 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2202};
2203
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204static const struct ieee80211_ops wl1271_ops = {
2205 .start = wl1271_op_start,
2206 .stop = wl1271_op_stop,
2207 .add_interface = wl1271_op_add_interface,
2208 .remove_interface = wl1271_op_remove_interface,
2209 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002210 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002211 .configure_filter = wl1271_op_configure_filter,
2212 .tx = wl1271_op_tx,
2213 .set_key = wl1271_op_set_key,
2214 .hw_scan = wl1271_op_hw_scan,
2215 .bss_info_changed = wl1271_op_bss_info_changed,
2216 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002217 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002218 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002219 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002220 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221};
2222
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002223
2224u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2225{
2226 u8 idx;
2227
2228 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2229
2230 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2231 wl1271_error("Illegal RX rate from HW: %d", rate);
2232 return 0;
2233 }
2234
2235 idx = wl1271_band_rate_to_idx[wl->band][rate];
2236 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2237 wl1271_error("Unsupported RX rate from HW: %d", rate);
2238 return 0;
2239 }
2240
2241 return idx;
2242}
2243
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002244static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2245 struct device_attribute *attr,
2246 char *buf)
2247{
2248 struct wl1271 *wl = dev_get_drvdata(dev);
2249 ssize_t len;
2250
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002251 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002252
2253 mutex_lock(&wl->mutex);
2254 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2255 wl->sg_enabled);
2256 mutex_unlock(&wl->mutex);
2257
2258 return len;
2259
2260}
2261
2262static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2263 struct device_attribute *attr,
2264 const char *buf, size_t count)
2265{
2266 struct wl1271 *wl = dev_get_drvdata(dev);
2267 unsigned long res;
2268 int ret;
2269
2270 ret = strict_strtoul(buf, 10, &res);
2271
2272 if (ret < 0) {
2273 wl1271_warning("incorrect value written to bt_coex_mode");
2274 return count;
2275 }
2276
2277 mutex_lock(&wl->mutex);
2278
2279 res = !!res;
2280
2281 if (res == wl->sg_enabled)
2282 goto out;
2283
2284 wl->sg_enabled = res;
2285
2286 if (wl->state == WL1271_STATE_OFF)
2287 goto out;
2288
2289 ret = wl1271_ps_elp_wakeup(wl, false);
2290 if (ret < 0)
2291 goto out;
2292
2293 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2294 wl1271_ps_elp_sleep(wl);
2295
2296 out:
2297 mutex_unlock(&wl->mutex);
2298 return count;
2299}
2300
2301static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2302 wl1271_sysfs_show_bt_coex_state,
2303 wl1271_sysfs_store_bt_coex_state);
2304
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002305static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2306 struct device_attribute *attr,
2307 char *buf)
2308{
2309 struct wl1271 *wl = dev_get_drvdata(dev);
2310 ssize_t len;
2311
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002312 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002313
2314 mutex_lock(&wl->mutex);
2315 if (wl->hw_pg_ver >= 0)
2316 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2317 else
2318 len = snprintf(buf, len, "n/a\n");
2319 mutex_unlock(&wl->mutex);
2320
2321 return len;
2322}
2323
2324static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2325 wl1271_sysfs_show_hw_pg_ver, NULL);
2326
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002327int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328{
2329 int ret;
2330
2331 if (wl->mac80211_registered)
2332 return 0;
2333
2334 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2335
2336 ret = ieee80211_register_hw(wl->hw);
2337 if (ret < 0) {
2338 wl1271_error("unable to register mac80211 hw: %d", ret);
2339 return ret;
2340 }
2341
2342 wl->mac80211_registered = true;
2343
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002344 register_netdevice_notifier(&wl1271_dev_notifier);
2345
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002346 wl1271_notice("loaded");
2347
2348 return 0;
2349}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002350EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002352void wl1271_unregister_hw(struct wl1271 *wl)
2353{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002354 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002355 ieee80211_unregister_hw(wl->hw);
2356 wl->mac80211_registered = false;
2357
2358}
2359EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2360
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002361int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002363 /* The tx descriptor buffer and the TKIP space. */
2364 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2365 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366
2367 /* unit us */
2368 /* FIXME: find a proper value */
2369 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002370 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371
2372 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002373 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002374 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002375 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002376 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002377 IEEE80211_HW_CONNECTION_MONITOR |
2378 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002380 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2381 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382 wl->hw->wiphy->max_scan_ssids = 1;
2383 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002384 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002385
Kalle Valo12bd8942010-03-18 12:26:33 +02002386 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002387 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002388
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002389 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390
2391 return 0;
2392}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002393EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002396
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002397struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002400 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002401 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002402 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403
2404 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2405 if (!hw) {
2406 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002407 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002408 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409 }
2410
Julia Lawall929ebd32010-05-15 23:16:39 +02002411 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002412 if (!plat_dev) {
2413 wl1271_error("could not allocate platform_device");
2414 ret = -ENOMEM;
2415 goto err_plat_alloc;
2416 }
2417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418 wl = hw->priv;
2419 memset(wl, 0, sizeof(*wl));
2420
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002421 INIT_LIST_HEAD(&wl->list);
2422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002424 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002425
2426 skb_queue_head_init(&wl->tx_queue);
2427
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002428 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002429 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002431 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002432 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 wl->rx_counter = 0;
2434 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2435 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002436 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002438 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002439 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002440 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2441 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002442 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002443 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002444 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002445 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002446 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002448 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449 wl->tx_frames[i] = NULL;
2450
2451 spin_lock_init(&wl->wl_lock);
2452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 wl->state = WL1271_STATE_OFF;
2454 mutex_init(&wl->mutex);
2455
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002456 /* Apply default driver configuration. */
2457 wl1271_conf_init(wl);
2458
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002459 wl1271_debugfs_init(wl);
2460
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002461 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002462 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002463 if (ret) {
2464 wl1271_error("couldn't register platform device");
2465 goto err_hw;
2466 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002467 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002468
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002469 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002470 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002471 if (ret < 0) {
2472 wl1271_error("failed to create sysfs file bt_coex_state");
2473 goto err_platform;
2474 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002475
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002476 /* Create sysfs file to get HW PG version */
2477 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2478 if (ret < 0) {
2479 wl1271_error("failed to create sysfs file hw_pg_ver");
2480 goto err_bt_coex_state;
2481 }
2482
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002483 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002484
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002485err_bt_coex_state:
2486 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2487
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002488err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002489 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002490
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002491err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002492 wl1271_debugfs_exit(wl);
2493 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002494
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002495err_plat_alloc:
2496 ieee80211_free_hw(hw);
2497
2498err_hw_alloc:
2499
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002500 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002501}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002502EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002503
2504int wl1271_free_hw(struct wl1271 *wl)
2505{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002506 platform_device_unregister(wl->plat_dev);
2507 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002508
2509 wl1271_debugfs_exit(wl);
2510
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002511 vfree(wl->fw);
2512 wl->fw = NULL;
2513 kfree(wl->nvs);
2514 wl->nvs = NULL;
2515
2516 kfree(wl->fw_status);
2517 kfree(wl->tx_res_if);
2518
2519 ieee80211_free_hw(wl->hw);
2520
2521 return 0;
2522}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002523EXPORT_SYMBOL_GPL(wl1271_free_hw);
2524
2525MODULE_LICENSE("GPL");
2526MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2527MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");