blob: 4b8f3662101fa56e13276dc446e56bbdd493c9be [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);
637 return 0;
638}
639
640static int wl1271_chip_wakeup(struct wl1271 *wl)
641{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300642 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300643 int ret = 0;
644
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200645 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200646 ret = wl1271_power_on(wl);
647 if (ret < 0)
648 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200650 wl1271_io_reset(wl);
651 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652
653 /* We don't need a real memory partition here, because we only want
654 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300655 memset(&partition, 0, sizeof(partition));
656 partition.reg.start = REGISTERS_BASE;
657 partition.reg.size = REGISTERS_DOWN_SIZE;
658 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659
660 /* ELP module wake up */
661 wl1271_fw_wakeup(wl);
662
663 /* whal_FwCtrl_BootSm() */
664
665 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200666 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667
668 /* 1. check if chip id is valid */
669
670 switch (wl->chip.id) {
671 case CHIP_ID_1271_PG10:
672 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
673 wl->chip.id);
674
675 ret = wl1271_setup(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 break;
679 case CHIP_ID_1271_PG20:
680 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
681 wl->chip.id);
682
683 ret = wl1271_setup(wl);
684 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 break;
687 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200688 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 }
692
693 if (wl->fw == NULL) {
694 ret = wl1271_fetch_firmware(wl);
695 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200696 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 }
698
699 /* No NVS from netlink, try to get it from the filesystem */
700 if (wl->nvs == NULL) {
701 ret = wl1271_fetch_nvs(wl);
702 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704 }
705
706out:
707 return ret;
708}
709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710int wl1271_plt_start(struct wl1271 *wl)
711{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200712 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 int ret;
714
715 mutex_lock(&wl->mutex);
716
717 wl1271_notice("power up");
718
719 if (wl->state != WL1271_STATE_OFF) {
720 wl1271_error("cannot go into PLT state because not "
721 "in off state: %d", wl->state);
722 ret = -EBUSY;
723 goto out;
724 }
725
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726 while (retries) {
727 retries--;
728 ret = wl1271_chip_wakeup(wl);
729 if (ret < 0)
730 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200732 ret = wl1271_boot(wl);
733 if (ret < 0)
734 goto power_off;
735
736 ret = wl1271_plt_init(wl);
737 if (ret < 0)
738 goto irq_disable;
739
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200740 wl->state = WL1271_STATE_PLT;
741 wl1271_notice("firmware booted in PLT mode (%s)",
742 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 goto out;
744
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745irq_disable:
746 wl1271_disable_interrupts(wl);
747 mutex_unlock(&wl->mutex);
748 /* Unlocking the mutex in the middle of handling is
749 inherently unsafe. In this case we deem it safe to do,
750 because we need to let any possibly pending IRQ out of
751 the system (and while we are WL1271_STATE_OFF the IRQ
752 work function will not do anything.) Also, any other
753 possible concurrent operations will fail due to the
754 current state, hence the wl1271 struct should be safe. */
755 cancel_work_sync(&wl->irq_work);
756 mutex_lock(&wl->mutex);
757power_off:
758 wl1271_power_off(wl);
759 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200761 wl1271_error("firmware boot in PLT mode failed despite %d retries",
762 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763out:
764 mutex_unlock(&wl->mutex);
765
766 return ret;
767}
768
769int wl1271_plt_stop(struct wl1271 *wl)
770{
771 int ret = 0;
772
773 mutex_lock(&wl->mutex);
774
775 wl1271_notice("power down");
776
777 if (wl->state != WL1271_STATE_PLT) {
778 wl1271_error("cannot power down because not in PLT "
779 "state: %d", wl->state);
780 ret = -EBUSY;
781 goto out;
782 }
783
784 wl1271_disable_interrupts(wl);
785 wl1271_power_off(wl);
786
787 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300788 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790out:
791 mutex_unlock(&wl->mutex);
792
793 return ret;
794}
795
796
797static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
798{
799 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200800 struct ieee80211_conf *conf = &hw->conf;
801 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
802 struct ieee80211_sta *sta = txinfo->control.sta;
803 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200805 /* peek into the rates configured in the STA entry */
806 spin_lock_irqsave(&wl->wl_lock, flags);
807 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
808 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
809 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
810 }
811 spin_unlock_irqrestore(&wl->wl_lock, flags);
812
813 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814 skb_queue_tail(&wl->tx_queue, skb);
815
816 /*
817 * The chip specific setup must run before the first TX packet -
818 * before that, the tx_work will not be initialized!
819 */
820
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300821 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822
823 /*
824 * The workqueue is slow to process the tx_queue and we need stop
825 * the queue here, otherwise the queue will get too long.
826 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200827 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
828 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200830 spin_lock_irqsave(&wl->wl_lock, flags);
831 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200832 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200833 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 }
835
836 return NETDEV_TX_OK;
837}
838
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300839static struct notifier_block wl1271_dev_notifier = {
840 .notifier_call = wl1271_dev_notify,
841};
842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843static int wl1271_op_start(struct ieee80211_hw *hw)
844{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200845 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
846
847 /*
848 * We have to delay the booting of the hardware because
849 * we need to know the local MAC address before downloading and
850 * initializing the firmware. The MAC address cannot be changed
851 * after boot, and without the proper MAC address, the firmware
852 * will not function properly.
853 *
854 * The MAC address is first known when the corresponding interface
855 * is added. That is where we will initialize the hardware.
856 */
857
858 return 0;
859}
860
861static void wl1271_op_stop(struct ieee80211_hw *hw)
862{
863 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
864}
865
866static int wl1271_op_add_interface(struct ieee80211_hw *hw,
867 struct ieee80211_vif *vif)
868{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400870 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200871 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872 int ret = 0;
873
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200874 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
875 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876
877 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200878 if (wl->vif) {
879 ret = -EBUSY;
880 goto out;
881 }
882
883 wl->vif = vif;
884
885 switch (vif->type) {
886 case NL80211_IFTYPE_STATION:
887 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200888 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200889 break;
890 case NL80211_IFTYPE_ADHOC:
891 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200892 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200893 break;
894 default:
895 ret = -EOPNOTSUPP;
896 goto out;
897 }
898
899 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900
901 if (wl->state != WL1271_STATE_OFF) {
902 wl1271_error("cannot start because not in off state: %d",
903 wl->state);
904 ret = -EBUSY;
905 goto out;
906 }
907
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200908 while (retries) {
909 retries--;
910 ret = wl1271_chip_wakeup(wl);
911 if (ret < 0)
912 goto power_off;
913
914 ret = wl1271_boot(wl);
915 if (ret < 0)
916 goto power_off;
917
918 ret = wl1271_hw_init(wl);
919 if (ret < 0)
920 goto irq_disable;
921
922 wl->state = WL1271_STATE_ON;
923 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400924
925 /* update hw/fw version info in wiphy struct */
926 wiphy->hw_version = wl->chip.id;
927 strncpy(wiphy->fw_version, wl->chip.fw_ver,
928 sizeof(wiphy->fw_version));
929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930 goto out;
931
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200932irq_disable:
933 wl1271_disable_interrupts(wl);
934 mutex_unlock(&wl->mutex);
935 /* Unlocking the mutex in the middle of handling is
936 inherently unsafe. In this case we deem it safe to do,
937 because we need to let any possibly pending IRQ out of
938 the system (and while we are WL1271_STATE_OFF the IRQ
939 work function will not do anything.) Also, any other
940 possible concurrent operations will fail due to the
941 current state, hence the wl1271 struct should be safe. */
942 cancel_work_sync(&wl->irq_work);
943 mutex_lock(&wl->mutex);
944power_off:
945 wl1271_power_off(wl);
946 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200948 wl1271_error("firmware boot failed despite %d retries",
949 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300950out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 mutex_unlock(&wl->mutex);
952
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300953 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300954 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 return ret;
957}
958
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200959static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
960 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961{
962 struct wl1271 *wl = hw->priv;
963 int i;
964
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200965 mutex_lock(&wl->mutex);
966 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200968 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300970 list_del(&wl->list);
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 WARN_ON(wl->state != WL1271_STATE_ON);
973
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300974 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300975 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300976 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300977
Luciano Coelho08688d62010-07-08 17:50:07 +0300978 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +0300979 wl->scan.state = WL1271_SCAN_STATE_IDLE;
980 kfree(wl->scan.scanned_ch);
981 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +0300982 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 }
984
985 wl->state = WL1271_STATE_OFF;
986
987 wl1271_disable_interrupts(wl);
988
989 mutex_unlock(&wl->mutex);
990
991 cancel_work_sync(&wl->irq_work);
992 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300993 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994
995 mutex_lock(&wl->mutex);
996
997 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300998 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 wl1271_power_off(wl);
1000
1001 memset(wl->bssid, 0, ETH_ALEN);
1002 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1003 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001005 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001006 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
1008 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001009 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1011 wl->tx_blocks_available = 0;
1012 wl->tx_results_count = 0;
1013 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001014 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001015 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->time_offset = 0;
1017 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001018 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1019 wl->sta_rate_set = 0;
1020 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001021 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001022 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 for (i = 0; i < NUM_TX_QUEUES; i++)
1025 wl->tx_blocks_freed[i] = 0;
1026
1027 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001028
1029 kfree(wl->fw_status);
1030 wl->fw_status = NULL;
1031 kfree(wl->tx_res_if);
1032 wl->tx_res_if = NULL;
1033 kfree(wl->target_mem_map);
1034 wl->target_mem_map = NULL;
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 mutex_unlock(&wl->mutex);
1037}
1038
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001039static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1040{
1041 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1042 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1043
1044 /* combine requested filters with current filter config */
1045 filters = wl->filters | filters;
1046
1047 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1048
1049 if (filters & FIF_PROMISC_IN_BSS) {
1050 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1051 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1052 wl->rx_config |= CFG_BSSID_FILTER_EN;
1053 }
1054 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1055 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1056 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1057 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1058 }
1059 if (filters & FIF_OTHER_BSS) {
1060 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1061 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1062 }
1063 if (filters & FIF_CONTROL) {
1064 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1065 wl->rx_filter |= CFG_RX_CTL_EN;
1066 }
1067 if (filters & FIF_FCSFAIL) {
1068 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1069 wl->rx_filter |= CFG_RX_FCS_ERROR;
1070 }
1071}
1072
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001073static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001074{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001075 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001076 /* we need to use a dummy BSSID for now */
1077 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1078 0xad, 0xbe, 0xef };
1079
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001080 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1081
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001082 /* pass through frames from all BSS */
1083 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1084
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001085 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001086 if (ret < 0)
1087 goto out;
1088
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001089 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001090
1091out:
1092 return ret;
1093}
1094
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001095static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001096{
1097 int ret;
1098
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001099 /*
1100 * One of the side effects of the JOIN command is that is clears
1101 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1102 * to a WPA/WPA2 access point will therefore kill the data-path.
1103 * Currently there is no supported scenario for JOIN during
1104 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1105 * must be handled somehow.
1106 *
1107 */
1108 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1109 wl1271_info("JOIN while associated.");
1110
1111 if (set_assoc)
1112 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1113
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001114 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1115 if (ret < 0)
1116 goto out;
1117
1118 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1119
1120 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1121 goto out;
1122
1123 /*
1124 * The join command disable the keep-alive mode, shut down its process,
1125 * and also clear the template config, so we need to reset it all after
1126 * the join. The acx_aid starts the keep-alive process, and the order
1127 * of the commands below is relevant.
1128 */
1129 ret = wl1271_acx_keep_alive_mode(wl, true);
1130 if (ret < 0)
1131 goto out;
1132
1133 ret = wl1271_acx_aid(wl, wl->aid);
1134 if (ret < 0)
1135 goto out;
1136
1137 ret = wl1271_cmd_build_klv_null_data(wl);
1138 if (ret < 0)
1139 goto out;
1140
1141 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1142 ACX_KEEP_ALIVE_TPL_VALID);
1143 if (ret < 0)
1144 goto out;
1145
1146out:
1147 return ret;
1148}
1149
1150static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001151{
1152 int ret;
1153
1154 /* to stop listening to a channel, we disconnect */
1155 ret = wl1271_cmd_disconnect(wl);
1156 if (ret < 0)
1157 goto out;
1158
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001159 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001160 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001161
1162 /* stop filterting packets based on bssid */
1163 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001164
1165out:
1166 return ret;
1167}
1168
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001169static void wl1271_set_band_rate(struct wl1271 *wl)
1170{
1171 if (wl->band == IEEE80211_BAND_2GHZ)
1172 wl->basic_rate_set = wl->conf.tx.basic_rate;
1173 else
1174 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1175}
1176
1177static u32 wl1271_min_rate_get(struct wl1271 *wl)
1178{
1179 int i;
1180 u32 rate = 0;
1181
1182 if (!wl->basic_rate_set) {
1183 WARN_ON(1);
1184 wl->basic_rate_set = wl->conf.tx.basic_rate;
1185 }
1186
1187 for (i = 0; !rate; i++) {
1188 if ((wl->basic_rate_set >> i) & 0x1)
1189 rate = 1 << i;
1190 }
1191
1192 return rate;
1193}
1194
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001195static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1196{
1197 int ret;
1198
1199 if (idle) {
1200 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1201 ret = wl1271_unjoin(wl);
1202 if (ret < 0)
1203 goto out;
1204 }
1205 wl->rate_set = wl1271_min_rate_get(wl);
1206 wl->sta_rate_set = 0;
1207 ret = wl1271_acx_rate_policies(wl);
1208 if (ret < 0)
1209 goto out;
1210 ret = wl1271_acx_keep_alive_config(
1211 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1212 ACX_KEEP_ALIVE_TPL_INVALID);
1213 if (ret < 0)
1214 goto out;
1215 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1216 } else {
1217 /* increment the session counter */
1218 wl->session_counter++;
1219 if (wl->session_counter >= SESSION_COUNTER_MAX)
1220 wl->session_counter = 0;
1221 ret = wl1271_dummy_join(wl);
1222 if (ret < 0)
1223 goto out;
1224 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1225 }
1226
1227out:
1228 return ret;
1229}
1230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1232{
1233 struct wl1271 *wl = hw->priv;
1234 struct ieee80211_conf *conf = &hw->conf;
1235 int channel, ret = 0;
1236
1237 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1238
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001239 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240 channel,
1241 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001242 conf->power_level,
1243 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001245 /*
1246 * mac80211 will go to idle nearly immediately after transmitting some
1247 * frames, such as the deauth. To make sure those frames reach the air,
1248 * wait here until the TX queue is fully flushed.
1249 */
1250 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1251 (conf->flags & IEEE80211_CONF_IDLE))
1252 wl1271_tx_flush(wl);
1253
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 mutex_lock(&wl->mutex);
1255
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001256 if (unlikely(wl->state == WL1271_STATE_OFF))
1257 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259 ret = wl1271_ps_elp_wakeup(wl, false);
1260 if (ret < 0)
1261 goto out;
1262
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001263 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001264 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1265 ((wl->band != conf->channel->band) ||
1266 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001267 wl->band = conf->channel->band;
1268 wl->channel = channel;
1269
1270 /*
1271 * FIXME: the mac80211 should really provide a fixed rate
1272 * to use here. for now, just use the smallest possible rate
1273 * for the band as a fixed rate for association frames and
1274 * other control messages.
1275 */
1276 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1277 wl1271_set_band_rate(wl);
1278
1279 wl->basic_rate = wl1271_min_rate_get(wl);
1280 ret = wl1271_acx_rate_policies(wl);
1281 if (ret < 0)
1282 wl1271_warning("rate policy for update channel "
1283 "failed %d", ret);
1284
1285 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001286 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001287 if (ret < 0)
1288 wl1271_warning("cmd join to update channel "
1289 "failed %d", ret);
1290 }
1291 }
1292
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001293 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001294 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1295 if (ret < 0)
1296 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 }
1298
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001299 /*
1300 * if mac80211 changes the PSM mode, make sure the mode is not
1301 * incorrectly changed after the pspoll failure active window.
1302 */
1303 if (changed & IEEE80211_CONF_CHANGE_PS)
1304 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1305
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001306 if (conf->flags & IEEE80211_CONF_PS &&
1307 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1308 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309
1310 /*
1311 * We enter PSM only if we're already associated.
1312 * If we're not, we'll enter it when joining an SSID,
1313 * through the bss_info_changed() hook.
1314 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001315 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001316 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001317 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001318 wl->basic_rate_set, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001319 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001321 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001322 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001324 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001326 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001327 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001328 wl->basic_rate_set, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 }
1330
1331 if (conf->power_level != wl->power_level) {
1332 ret = wl1271_acx_tx_power(wl, conf->power_level);
1333 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001334 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
1336 wl->power_level = conf->power_level;
1337 }
1338
1339out_sleep:
1340 wl1271_ps_elp_sleep(wl);
1341
1342out:
1343 mutex_unlock(&wl->mutex);
1344
1345 return ret;
1346}
1347
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348struct wl1271_filter_params {
1349 bool enabled;
1350 int mc_list_length;
1351 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1352};
1353
Jiri Pirko22bedad2010-04-01 21:22:57 +00001354static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1355 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001356{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001357 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001358 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001359 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001361 if (unlikely(wl->state == WL1271_STATE_OFF))
1362 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001363
Juuso Oikarinen74441132009-10-13 12:47:53 +03001364 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001365 if (!fp) {
1366 wl1271_error("Out of memory setting filters.");
1367 return 0;
1368 }
1369
1370 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001371 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001372 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1373 fp->enabled = false;
1374 } else {
1375 fp->enabled = true;
1376 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001377 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001378 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001379 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001380 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001381 }
1382
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001384}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001386#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1387 FIF_ALLMULTI | \
1388 FIF_FCSFAIL | \
1389 FIF_BCN_PRBRESP_PROMISC | \
1390 FIF_CONTROL | \
1391 FIF_OTHER_BSS)
1392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1394 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001395 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001397 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001399 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
1401 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1402
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001403 mutex_lock(&wl->mutex);
1404
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001405 *total &= WL1271_SUPPORTED_FILTERS;
1406 changed &= WL1271_SUPPORTED_FILTERS;
1407
1408 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001409 goto out;
1410
1411 ret = wl1271_ps_elp_wakeup(wl, false);
1412 if (ret < 0)
1413 goto out;
1414
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001416 if (*total & FIF_ALLMULTI)
1417 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1418 else if (fp)
1419 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1420 fp->mc_list,
1421 fp->mc_list_length);
1422 if (ret < 0)
1423 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001425 /* determine, whether supported filter values have changed */
1426 if (changed == 0)
1427 goto out_sleep;
1428
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001429 /* configure filters */
1430 wl->filters = *total;
1431 wl1271_configure_filters(wl, 0);
1432
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001433 /* apply configured filters */
1434 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1435 if (ret < 0)
1436 goto out_sleep;
1437
1438out_sleep:
1439 wl1271_ps_elp_sleep(wl);
1440
1441out:
1442 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001443 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444}
1445
1446static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1447 struct ieee80211_vif *vif,
1448 struct ieee80211_sta *sta,
1449 struct ieee80211_key_conf *key_conf)
1450{
1451 struct wl1271 *wl = hw->priv;
1452 const u8 *addr;
1453 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001454 u32 tx_seq_32 = 0;
1455 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 u8 key_type;
1457
1458 static const u8 bcast_addr[ETH_ALEN] =
1459 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1460
1461 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1462
1463 addr = sta ? sta->addr : bcast_addr;
1464
1465 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1466 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1467 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001468 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469 key_conf->keylen, key_conf->flags);
1470 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1471
1472 if (is_zero_ether_addr(addr)) {
1473 /* We dont support TX only encryption */
1474 ret = -EOPNOTSUPP;
1475 goto out;
1476 }
1477
1478 mutex_lock(&wl->mutex);
1479
1480 ret = wl1271_ps_elp_wakeup(wl, false);
1481 if (ret < 0)
1482 goto out_unlock;
1483
Johannes Berg97359d12010-08-10 09:46:38 +02001484 switch (key_conf->cipher) {
1485 case WLAN_CIPHER_SUITE_WEP40:
1486 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 key_type = KEY_WEP;
1488
1489 key_conf->hw_key_idx = key_conf->keyidx;
1490 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001491 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 key_type = KEY_TKIP;
1493
1494 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001495 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1496 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001498 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 key_type = KEY_AES;
1500
1501 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001502 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1503 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 break;
1505 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001506 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507
1508 ret = -EOPNOTSUPP;
1509 goto out_sleep;
1510 }
1511
1512 switch (cmd) {
1513 case SET_KEY:
1514 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1515 key_conf->keyidx, key_type,
1516 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001517 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 if (ret < 0) {
1519 wl1271_error("Could not add or replace key");
1520 goto out_sleep;
1521 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001522
1523 /* the default WEP key needs to be configured at least once */
1524 if (key_type == KEY_WEP) {
1525 ret = wl1271_cmd_set_default_wep_key(wl,
1526 wl->default_key);
1527 if (ret < 0)
1528 goto out_sleep;
1529 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 break;
1531
1532 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001533 /* The wl1271 does not allow to remove unicast keys - they
1534 will be cleared automatically on next CMD_JOIN. Ignore the
1535 request silently, as we dont want the mac80211 to emit
1536 an error message. */
1537 if (!is_broadcast_ether_addr(addr))
1538 break;
1539
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1541 key_conf->keyidx, key_type,
1542 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001543 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 if (ret < 0) {
1545 wl1271_error("Could not remove key");
1546 goto out_sleep;
1547 }
1548 break;
1549
1550 default:
1551 wl1271_error("Unsupported key cmd 0x%x", cmd);
1552 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553 break;
1554 }
1555
1556out_sleep:
1557 wl1271_ps_elp_sleep(wl);
1558
1559out_unlock:
1560 mutex_unlock(&wl->mutex);
1561
1562out:
1563 return ret;
1564}
1565
1566static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001567 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001568 struct cfg80211_scan_request *req)
1569{
1570 struct wl1271 *wl = hw->priv;
1571 int ret;
1572 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001573 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
1575 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1576
1577 if (req->n_ssids) {
1578 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001579 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 }
1581
1582 mutex_lock(&wl->mutex);
1583
1584 ret = wl1271_ps_elp_wakeup(wl, false);
1585 if (ret < 0)
1586 goto out;
1587
Luciano Coelho5924f892010-08-04 03:46:22 +03001588 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001589
1590 wl1271_ps_elp_sleep(wl);
1591
1592out:
1593 mutex_unlock(&wl->mutex);
1594
1595 return ret;
1596}
1597
1598static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1599{
1600 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001601 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602
1603 mutex_lock(&wl->mutex);
1604
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001605 if (unlikely(wl->state == WL1271_STATE_OFF))
1606 goto out;
1607
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 ret = wl1271_ps_elp_wakeup(wl, false);
1609 if (ret < 0)
1610 goto out;
1611
1612 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1613 if (ret < 0)
1614 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1615
1616 wl1271_ps_elp_sleep(wl);
1617
1618out:
1619 mutex_unlock(&wl->mutex);
1620
1621 return ret;
1622}
1623
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001624static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1625{
1626 u8 *ptr = beacon->data +
1627 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1628
1629 /* find the location of the ssid in the beacon */
1630 while (ptr < beacon->data + beacon->len) {
1631 if (ptr[0] == WLAN_EID_SSID) {
1632 wl->ssid_len = ptr[1];
1633 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1634 return;
1635 }
1636 ptr += ptr[1];
1637 }
1638 wl1271_error("ad-hoc beacon template has no SSID!\n");
1639}
1640
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001641static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1642 struct ieee80211_vif *vif,
1643 struct ieee80211_bss_conf *bss_conf,
1644 u32 changed)
1645{
1646 enum wl1271_cmd_ps_mode mode;
1647 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001648 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001649 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 int ret;
1651
1652 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1653
1654 mutex_lock(&wl->mutex);
1655
1656 ret = wl1271_ps_elp_wakeup(wl, false);
1657 if (ret < 0)
1658 goto out;
1659
Eliad Peller9ee82d52010-09-19 18:55:09 +02001660 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001661 (wl->bss_type == BSS_TYPE_IBSS)) {
1662 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1663 bss_conf->beacon_int);
1664
1665 wl->beacon_int = bss_conf->beacon_int;
1666 do_join = true;
1667 }
1668
Eliad Peller9ee82d52010-09-19 18:55:09 +02001669 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001670 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001671 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1672
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001673 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1674
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001675 if (beacon) {
1676 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001677
1678 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001679 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1680 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001681 beacon->len, 0,
1682 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683
1684 if (ret < 0) {
1685 dev_kfree_skb(beacon);
1686 goto out_sleep;
1687 }
1688
1689 hdr = (struct ieee80211_hdr *) beacon->data;
1690 hdr->frame_control = cpu_to_le16(
1691 IEEE80211_FTYPE_MGMT |
1692 IEEE80211_STYPE_PROBE_RESP);
1693
1694 ret = wl1271_cmd_template_set(wl,
1695 CMD_TEMPL_PROBE_RESPONSE,
1696 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001697 beacon->len, 0,
1698 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001699 dev_kfree_skb(beacon);
1700 if (ret < 0)
1701 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001702
1703 /* Need to update the SSID (for filtering etc) */
1704 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001705 }
1706 }
1707
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001708 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1709 (wl->bss_type == BSS_TYPE_IBSS)) {
1710 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1711 bss_conf->enable_beacon ? "enabled" : "disabled");
1712
1713 if (bss_conf->enable_beacon)
1714 wl->set_bss_type = BSS_TYPE_IBSS;
1715 else
1716 wl->set_bss_type = BSS_TYPE_STA_BSS;
1717 do_join = true;
1718 }
1719
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001720 if (changed & BSS_CHANGED_CQM) {
1721 bool enable = false;
1722 if (bss_conf->cqm_rssi_thold)
1723 enable = true;
1724 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1725 bss_conf->cqm_rssi_thold,
1726 bss_conf->cqm_rssi_hyst);
1727 if (ret < 0)
1728 goto out;
1729 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1730 }
1731
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001732 if ((changed & BSS_CHANGED_BSSID) &&
1733 /*
1734 * Now we know the correct bssid, so we send a new join command
1735 * and enable the BSSID filter
1736 */
1737 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001738 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001739
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001740 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001741 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001742 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001743
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001744 ret = wl1271_build_qos_null_data(wl);
1745 if (ret < 0)
1746 goto out_sleep;
1747
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001748 /* filter out all packets not from this BSSID */
1749 wl1271_configure_filters(wl, 0);
1750
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001751 /* Need to update the BSSID (for filtering etc) */
1752 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001753 }
1754
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755 if (changed & BSS_CHANGED_ASSOC) {
1756 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001757 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001758 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001759 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001760
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001761 wl->ps_poll_failures = 0;
1762
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001763 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001764 * use basic rates from AP, and determine lowest rate
1765 * to use with control frames.
1766 */
1767 rates = bss_conf->basic_rates;
1768 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1769 rates);
1770 wl->basic_rate = wl1271_min_rate_get(wl);
1771 ret = wl1271_acx_rate_policies(wl);
1772 if (ret < 0)
1773 goto out_sleep;
1774
1775 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001776 * with wl1271, we don't need to update the
1777 * beacon_int and dtim_period, because the firmware
1778 * updates it by itself when the first beacon is
1779 * received after a join.
1780 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001781 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1782 if (ret < 0)
1783 goto out_sleep;
1784
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001785 /*
1786 * The SSID is intentionally set to NULL here - the
1787 * firmware will set the probe request with a
1788 * broadcast SSID regardless of what we set in the
1789 * template.
1790 */
1791 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1792 NULL, 0, wl->band);
1793
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001794 /* enable the connection monitoring feature */
1795 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796 if (ret < 0)
1797 goto out_sleep;
1798
1799 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001800 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1801 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001803 ret = wl1271_ps_set_mode(wl, mode,
1804 wl->basic_rate_set,
1805 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 if (ret < 0)
1807 goto out_sleep;
1808 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001809 } else {
1810 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001811 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001812 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001813 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001814
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001815 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001816 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001817
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001818 /* revert back to minimum rates for the current band */
1819 wl1271_set_band_rate(wl);
1820 wl->basic_rate = wl1271_min_rate_get(wl);
1821 ret = wl1271_acx_rate_policies(wl);
1822 if (ret < 0)
1823 goto out_sleep;
1824
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001825 /* disable connection monitor features */
1826 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001827
1828 /* Disable the keep-alive feature */
1829 ret = wl1271_acx_keep_alive_mode(wl, false);
1830
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001831 if (ret < 0)
1832 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 if (changed & BSS_CHANGED_ERP_SLOT) {
1838 if (bss_conf->use_short_slot)
1839 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1840 else
1841 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1842 if (ret < 0) {
1843 wl1271_warning("Set slot time failed %d", ret);
1844 goto out_sleep;
1845 }
1846 }
1847
1848 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1849 if (bss_conf->use_short_preamble)
1850 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1851 else
1852 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1853 }
1854
1855 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1856 if (bss_conf->use_cts_prot)
1857 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1858 else
1859 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1860 if (ret < 0) {
1861 wl1271_warning("Set ctsprotect failed %d", ret);
1862 goto out_sleep;
1863 }
1864 }
1865
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001866 if (changed & BSS_CHANGED_ARP_FILTER) {
1867 __be32 addr = bss_conf->arp_addr_list[0];
1868 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1869
1870 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1871 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1872 else
1873 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1874
1875 if (ret < 0)
1876 goto out_sleep;
1877 }
1878
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001879 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001880 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001881 if (ret < 0) {
1882 wl1271_warning("cmd join failed %d", ret);
1883 goto out_sleep;
1884 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001885 }
1886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887out_sleep:
1888 wl1271_ps_elp_sleep(wl);
1889
1890out:
1891 mutex_unlock(&wl->mutex);
1892}
1893
Kalle Valoc6999d82010-02-18 13:25:41 +02001894static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1895 const struct ieee80211_tx_queue_params *params)
1896{
1897 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001898 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001899 int ret;
1900
1901 mutex_lock(&wl->mutex);
1902
1903 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1904
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001905 ret = wl1271_ps_elp_wakeup(wl, false);
1906 if (ret < 0)
1907 goto out;
1908
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001909 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001910 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1911 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001912 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001913 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001914 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001915
Kalle Valo4695dc92010-03-18 12:26:38 +02001916 if (params->uapsd)
1917 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1918 else
1919 ps_scheme = CONF_PS_SCHEME_LEGACY;
1920
Kalle Valoc6999d82010-02-18 13:25:41 +02001921 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1922 CONF_CHANNEL_TYPE_EDCF,
1923 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001924 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001925 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001926 goto out_sleep;
1927
1928out_sleep:
1929 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001930
1931out:
1932 mutex_unlock(&wl->mutex);
1933
1934 return ret;
1935}
1936
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001937static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1938{
1939
1940 struct wl1271 *wl = hw->priv;
1941 u64 mactime = ULLONG_MAX;
1942 int ret;
1943
1944 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1945
1946 mutex_lock(&wl->mutex);
1947
1948 ret = wl1271_ps_elp_wakeup(wl, false);
1949 if (ret < 0)
1950 goto out;
1951
1952 ret = wl1271_acx_tsf_info(wl, &mactime);
1953 if (ret < 0)
1954 goto out_sleep;
1955
1956out_sleep:
1957 wl1271_ps_elp_sleep(wl);
1958
1959out:
1960 mutex_unlock(&wl->mutex);
1961 return mactime;
1962}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963
John W. Linvilleece550d2010-07-28 16:41:06 -04001964static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
1965 struct survey_info *survey)
1966{
1967 struct wl1271 *wl = hw->priv;
1968 struct ieee80211_conf *conf = &hw->conf;
1969
1970 if (idx != 0)
1971 return -ENOENT;
1972
1973 survey->channel = conf->channel;
1974 survey->filled = SURVEY_INFO_NOISE_DBM;
1975 survey->noise = wl->noise;
1976
1977 return 0;
1978}
1979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980/* can't be const, mac80211 writes to this */
1981static struct ieee80211_rate wl1271_rates[] = {
1982 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001983 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1984 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001986 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1987 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1989 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001990 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1991 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1993 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001994 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1995 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1997 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001998 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1999 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002001 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2002 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002004 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2005 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002007 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2008 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002010 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2011 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002013 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2014 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002016 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2017 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002019 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2020 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021};
2022
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002023/*
2024 * Can't be const, mac80211 writes to this. The order of the channels here
2025 * is designed to improve scanning.
2026 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002028 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002029 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002030 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002031 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002032 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2033 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2034 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2035 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2036 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2037 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2038 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2039 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2040 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041};
2042
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002043/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002044static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002045 /* MCS rates are used only with 11n */
2046 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2047 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2048 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2049 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2050 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2051 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2052 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2053 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2054
2055 11, /* CONF_HW_RXTX_RATE_54 */
2056 10, /* CONF_HW_RXTX_RATE_48 */
2057 9, /* CONF_HW_RXTX_RATE_36 */
2058 8, /* CONF_HW_RXTX_RATE_24 */
2059
2060 /* TI-specific rate */
2061 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2062
2063 7, /* CONF_HW_RXTX_RATE_18 */
2064 6, /* CONF_HW_RXTX_RATE_12 */
2065 3, /* CONF_HW_RXTX_RATE_11 */
2066 5, /* CONF_HW_RXTX_RATE_9 */
2067 4, /* CONF_HW_RXTX_RATE_6 */
2068 2, /* CONF_HW_RXTX_RATE_5_5 */
2069 1, /* CONF_HW_RXTX_RATE_2 */
2070 0 /* CONF_HW_RXTX_RATE_1 */
2071};
2072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073/* can't be const, mac80211 writes to this */
2074static struct ieee80211_supported_band wl1271_band_2ghz = {
2075 .channels = wl1271_channels,
2076 .n_channels = ARRAY_SIZE(wl1271_channels),
2077 .bitrates = wl1271_rates,
2078 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2079};
2080
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002081/* 5 GHz data rates for WL1273 */
2082static struct ieee80211_rate wl1271_rates_5ghz[] = {
2083 { .bitrate = 60,
2084 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2085 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2086 { .bitrate = 90,
2087 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2088 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2089 { .bitrate = 120,
2090 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2091 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2092 { .bitrate = 180,
2093 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2094 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2095 { .bitrate = 240,
2096 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2097 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2098 { .bitrate = 360,
2099 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2100 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2101 { .bitrate = 480,
2102 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2103 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2104 { .bitrate = 540,
2105 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2106 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2107};
2108
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002109/*
2110 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2111 * The order of the channels here is designed to improve scanning.
2112 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002113static struct ieee80211_channel wl1271_channels_5ghz[] = {
2114 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002115 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002116 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002117 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002118 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002119 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002120 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002121 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002122 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002123 { .hw_value = 184, .center_freq = 4920},
2124 { .hw_value = 189, .center_freq = 4945},
2125 { .hw_value = 9, .center_freq = 5045},
2126 { .hw_value = 36, .center_freq = 5180},
2127 { .hw_value = 46, .center_freq = 5230},
2128 { .hw_value = 64, .center_freq = 5320},
2129 { .hw_value = 116, .center_freq = 5580},
2130 { .hw_value = 136, .center_freq = 5680},
2131 { .hw_value = 192, .center_freq = 4960},
2132 { .hw_value = 11, .center_freq = 5055},
2133 { .hw_value = 38, .center_freq = 5190},
2134 { .hw_value = 48, .center_freq = 5240},
2135 { .hw_value = 100, .center_freq = 5500},
2136 { .hw_value = 120, .center_freq = 5600},
2137 { .hw_value = 140, .center_freq = 5700},
2138 { .hw_value = 185, .center_freq = 4925},
2139 { .hw_value = 196, .center_freq = 4980},
2140 { .hw_value = 12, .center_freq = 5060},
2141 { .hw_value = 40, .center_freq = 5200},
2142 { .hw_value = 52, .center_freq = 5260},
2143 { .hw_value = 104, .center_freq = 5520},
2144 { .hw_value = 124, .center_freq = 5620},
2145 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002146 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002147 { .hw_value = 187, .center_freq = 4935},
2148 { .hw_value = 7, .center_freq = 5035},
2149 { .hw_value = 16, .center_freq = 5080},
2150 { .hw_value = 42, .center_freq = 5210},
2151 { .hw_value = 56, .center_freq = 5280},
2152 { .hw_value = 108, .center_freq = 5540},
2153 { .hw_value = 128, .center_freq = 5640},
2154 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002155 { .hw_value = 165, .center_freq = 5825},
2156};
2157
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002158/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002159static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002160 /* MCS rates are used only with 11n */
2161 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2162 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2163 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2164 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2165 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2166 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2167 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2168 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2169
2170 7, /* CONF_HW_RXTX_RATE_54 */
2171 6, /* CONF_HW_RXTX_RATE_48 */
2172 5, /* CONF_HW_RXTX_RATE_36 */
2173 4, /* CONF_HW_RXTX_RATE_24 */
2174
2175 /* TI-specific rate */
2176 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2177
2178 3, /* CONF_HW_RXTX_RATE_18 */
2179 2, /* CONF_HW_RXTX_RATE_12 */
2180 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2181 1, /* CONF_HW_RXTX_RATE_9 */
2182 0, /* CONF_HW_RXTX_RATE_6 */
2183 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2184 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2185 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2186};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002187
2188static struct ieee80211_supported_band wl1271_band_5ghz = {
2189 .channels = wl1271_channels_5ghz,
2190 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2191 .bitrates = wl1271_rates_5ghz,
2192 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2193};
2194
Tobias Klausera0ea9492010-05-20 10:38:11 +02002195static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002196 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2197 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2198};
2199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200static const struct ieee80211_ops wl1271_ops = {
2201 .start = wl1271_op_start,
2202 .stop = wl1271_op_stop,
2203 .add_interface = wl1271_op_add_interface,
2204 .remove_interface = wl1271_op_remove_interface,
2205 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002206 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207 .configure_filter = wl1271_op_configure_filter,
2208 .tx = wl1271_op_tx,
2209 .set_key = wl1271_op_set_key,
2210 .hw_scan = wl1271_op_hw_scan,
2211 .bss_info_changed = wl1271_op_bss_info_changed,
2212 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002213 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002214 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002215 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002216 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217};
2218
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002219
2220u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2221{
2222 u8 idx;
2223
2224 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2225
2226 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2227 wl1271_error("Illegal RX rate from HW: %d", rate);
2228 return 0;
2229 }
2230
2231 idx = wl1271_band_rate_to_idx[wl->band][rate];
2232 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2233 wl1271_error("Unsupported RX rate from HW: %d", rate);
2234 return 0;
2235 }
2236
2237 return idx;
2238}
2239
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002240static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2241 struct device_attribute *attr,
2242 char *buf)
2243{
2244 struct wl1271 *wl = dev_get_drvdata(dev);
2245 ssize_t len;
2246
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002247 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002248
2249 mutex_lock(&wl->mutex);
2250 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2251 wl->sg_enabled);
2252 mutex_unlock(&wl->mutex);
2253
2254 return len;
2255
2256}
2257
2258static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2259 struct device_attribute *attr,
2260 const char *buf, size_t count)
2261{
2262 struct wl1271 *wl = dev_get_drvdata(dev);
2263 unsigned long res;
2264 int ret;
2265
2266 ret = strict_strtoul(buf, 10, &res);
2267
2268 if (ret < 0) {
2269 wl1271_warning("incorrect value written to bt_coex_mode");
2270 return count;
2271 }
2272
2273 mutex_lock(&wl->mutex);
2274
2275 res = !!res;
2276
2277 if (res == wl->sg_enabled)
2278 goto out;
2279
2280 wl->sg_enabled = res;
2281
2282 if (wl->state == WL1271_STATE_OFF)
2283 goto out;
2284
2285 ret = wl1271_ps_elp_wakeup(wl, false);
2286 if (ret < 0)
2287 goto out;
2288
2289 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2290 wl1271_ps_elp_sleep(wl);
2291
2292 out:
2293 mutex_unlock(&wl->mutex);
2294 return count;
2295}
2296
2297static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2298 wl1271_sysfs_show_bt_coex_state,
2299 wl1271_sysfs_store_bt_coex_state);
2300
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002301static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2302 struct device_attribute *attr,
2303 char *buf)
2304{
2305 struct wl1271 *wl = dev_get_drvdata(dev);
2306 ssize_t len;
2307
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002308 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002309
2310 mutex_lock(&wl->mutex);
2311 if (wl->hw_pg_ver >= 0)
2312 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2313 else
2314 len = snprintf(buf, len, "n/a\n");
2315 mutex_unlock(&wl->mutex);
2316
2317 return len;
2318}
2319
2320static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2321 wl1271_sysfs_show_hw_pg_ver, NULL);
2322
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002323int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324{
2325 int ret;
2326
2327 if (wl->mac80211_registered)
2328 return 0;
2329
2330 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2331
2332 ret = ieee80211_register_hw(wl->hw);
2333 if (ret < 0) {
2334 wl1271_error("unable to register mac80211 hw: %d", ret);
2335 return ret;
2336 }
2337
2338 wl->mac80211_registered = true;
2339
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002340 register_netdevice_notifier(&wl1271_dev_notifier);
2341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 wl1271_notice("loaded");
2343
2344 return 0;
2345}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002346EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002348void wl1271_unregister_hw(struct wl1271 *wl)
2349{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002350 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002351 ieee80211_unregister_hw(wl->hw);
2352 wl->mac80211_registered = false;
2353
2354}
2355EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2356
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002357int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002359 /* The tx descriptor buffer and the TKIP space. */
2360 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2361 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362
2363 /* unit us */
2364 /* FIXME: find a proper value */
2365 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002366 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367
2368 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002369 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002370 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002371 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002372 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002373 IEEE80211_HW_CONNECTION_MONITOR |
2374 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002376 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2377 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378 wl->hw->wiphy->max_scan_ssids = 1;
2379 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002380 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002381
Kalle Valo12bd8942010-03-18 12:26:33 +02002382 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002383 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002384
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002385 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386
2387 return 0;
2388}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002389EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002392
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002393struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002396 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002397 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002398 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399
2400 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2401 if (!hw) {
2402 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002403 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002404 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405 }
2406
Julia Lawall929ebd32010-05-15 23:16:39 +02002407 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002408 if (!plat_dev) {
2409 wl1271_error("could not allocate platform_device");
2410 ret = -ENOMEM;
2411 goto err_plat_alloc;
2412 }
2413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002414 wl = hw->priv;
2415 memset(wl, 0, sizeof(*wl));
2416
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002417 INIT_LIST_HEAD(&wl->list);
2418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002419 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002420 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002421
2422 skb_queue_head_init(&wl->tx_queue);
2423
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002424 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002425 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002426 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002427 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002428 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002429 wl->rx_counter = 0;
2430 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2431 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002432 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002434 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002435 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002436 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2437 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002438 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002439 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002440 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002441 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002442 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002444 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 wl->tx_frames[i] = NULL;
2446
2447 spin_lock_init(&wl->wl_lock);
2448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449 wl->state = WL1271_STATE_OFF;
2450 mutex_init(&wl->mutex);
2451
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002452 /* Apply default driver configuration. */
2453 wl1271_conf_init(wl);
2454
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002455 wl1271_debugfs_init(wl);
2456
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002457 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002458 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002459 if (ret) {
2460 wl1271_error("couldn't register platform device");
2461 goto err_hw;
2462 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002463 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002464
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002465 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002466 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002467 if (ret < 0) {
2468 wl1271_error("failed to create sysfs file bt_coex_state");
2469 goto err_platform;
2470 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002471
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002472 /* Create sysfs file to get HW PG version */
2473 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2474 if (ret < 0) {
2475 wl1271_error("failed to create sysfs file hw_pg_ver");
2476 goto err_bt_coex_state;
2477 }
2478
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002479 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002480
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002481err_bt_coex_state:
2482 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2483
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002484err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002485 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002486
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002487err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002488 wl1271_debugfs_exit(wl);
2489 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002490
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002491err_plat_alloc:
2492 ieee80211_free_hw(hw);
2493
2494err_hw_alloc:
2495
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002496 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002497}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002498EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002499
2500int wl1271_free_hw(struct wl1271 *wl)
2501{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002502 platform_device_unregister(wl->plat_dev);
2503 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002504
2505 wl1271_debugfs_exit(wl);
2506
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002507 vfree(wl->fw);
2508 wl->fw = NULL;
2509 kfree(wl->nvs);
2510 wl->nvs = NULL;
2511
2512 kfree(wl->fw_status);
2513 kfree(wl->tx_res_if);
2514
2515 ieee80211_free_hw(wl->hw);
2516
2517 return 0;
2518}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002519EXPORT_SYMBOL_GPL(wl1271_free_hw);
2520
2521MODULE_LICENSE("GPL");
2522MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2523MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");