blob: e7f096fb62126f652559cc03f5cc75bd8ba69253 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200217 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300218 .keep_alive_interval = 55000,
219 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200221 .itrim = {
222 .enable = false,
223 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200224 },
225 .pm_config = {
226 .host_clk_settling_time = 5000,
227 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300228 },
229 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 .trigger_pacing = 1,
231 .avg_weight_rssi_beacon = 20,
232 .avg_weight_rssi_data = 10,
233 .avg_weight_snr_beacon = 20,
234 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 }
236};
237
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200238static void wl1271_device_release(struct device *dev)
239{
240
241}
242
243static struct platform_device wl1271_device = {
244 .name = "wl1271",
245 .id = -1,
246
247 /* device model insists to have a release function */
248 .dev = {
249 .release = wl1271_device_release,
250 },
251};
252
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300253static LIST_HEAD(wl_list);
254
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300255static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
256 void *arg)
257{
258 struct net_device *dev = arg;
259 struct wireless_dev *wdev;
260 struct wiphy *wiphy;
261 struct ieee80211_hw *hw;
262 struct wl1271 *wl;
263 struct wl1271 *wl_temp;
264 int ret = 0;
265
266 /* Check that this notification is for us. */
267 if (what != NETDEV_CHANGE)
268 return NOTIFY_DONE;
269
270 wdev = dev->ieee80211_ptr;
271 if (wdev == NULL)
272 return NOTIFY_DONE;
273
274 wiphy = wdev->wiphy;
275 if (wiphy == NULL)
276 return NOTIFY_DONE;
277
278 hw = wiphy_priv(wiphy);
279 if (hw == NULL)
280 return NOTIFY_DONE;
281
282 wl_temp = hw->priv;
283 list_for_each_entry(wl, &wl_list, list) {
284 if (wl == wl_temp)
285 break;
286 }
287 if (wl != wl_temp)
288 return NOTIFY_DONE;
289
290 mutex_lock(&wl->mutex);
291
292 if (wl->state == WL1271_STATE_OFF)
293 goto out;
294
295 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
296 goto out;
297
298 ret = wl1271_ps_elp_wakeup(wl, false);
299 if (ret < 0)
300 goto out;
301
302 if ((dev->operstate == IF_OPER_UP) &&
303 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
304 wl1271_cmd_set_sta_state(wl);
305 wl1271_info("Association completed.");
306 }
307
308 wl1271_ps_elp_sleep(wl);
309
310out:
311 mutex_unlock(&wl->mutex);
312
313 return NOTIFY_OK;
314}
315
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300316static void wl1271_conf_init(struct wl1271 *wl)
317{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300318
319 /*
320 * This function applies the default configuration to the driver. This
321 * function is invoked upon driver load (spi probe.)
322 *
323 * The configuration is stored in a run-time structure in order to
324 * facilitate for run-time adjustment of any of the parameters. Making
325 * changes to the configuration structure will apply the new values on
326 * the next interface up (wl1271_op_start.)
327 */
328
329 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300330 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300331}
332
333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300334static int wl1271_plt_init(struct wl1271 *wl)
335{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200336 struct conf_tx_ac_category *conf_ac;
337 struct conf_tx_tid *conf_tid;
338 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300339
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200340 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200341 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200342 return ret;
343
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200344 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200345 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200346 return ret;
347
Luciano Coelho12419cc2010-02-18 13:25:44 +0200348 ret = wl1271_init_templates_config(wl);
349 if (ret < 0)
350 return ret;
351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352 ret = wl1271_acx_init_mem_config(wl);
353 if (ret < 0)
354 return ret;
355
Luciano Coelho12419cc2010-02-18 13:25:44 +0200356 /* PHY layer config */
357 ret = wl1271_init_phy_config(wl);
358 if (ret < 0)
359 goto out_free_memmap;
360
361 ret = wl1271_acx_dco_itrim_params(wl);
362 if (ret < 0)
363 goto out_free_memmap;
364
365 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200366 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200367 if (ret < 0)
368 goto out_free_memmap;
369
370 /* Bluetooth WLAN coexistence */
371 ret = wl1271_init_pta(wl);
372 if (ret < 0)
373 goto out_free_memmap;
374
375 /* Energy detection */
376 ret = wl1271_init_energy_detection(wl);
377 if (ret < 0)
378 goto out_free_memmap;
379
380 /* Default fragmentation threshold */
381 ret = wl1271_acx_frag_threshold(wl);
382 if (ret < 0)
383 goto out_free_memmap;
384
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200385 /* Default TID/AC configuration */
386 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200387 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200388 conf_ac = &wl->conf.tx.ac_conf[i];
389 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
390 conf_ac->cw_max, conf_ac->aifsn,
391 conf_ac->tx_op_limit);
392 if (ret < 0)
393 goto out_free_memmap;
394
Luciano Coelho12419cc2010-02-18 13:25:44 +0200395 conf_tid = &wl->conf.tx.tid_conf[i];
396 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
397 conf_tid->channel_type,
398 conf_tid->tsid,
399 conf_tid->ps_scheme,
400 conf_tid->ack_policy,
401 conf_tid->apsd_conf[0],
402 conf_tid->apsd_conf[1]);
403 if (ret < 0)
404 goto out_free_memmap;
405 }
406
Luciano Coelho12419cc2010-02-18 13:25:44 +0200407 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200408 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200410 goto out_free_memmap;
411
412 /* Configure for CAM power saving (ie. always active) */
413 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
414 if (ret < 0)
415 goto out_free_memmap;
416
417 /* configure PM */
418 ret = wl1271_acx_pm_config(wl);
419 if (ret < 0)
420 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421
422 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200423
424 out_free_memmap:
425 kfree(wl->target_mem_map);
426 wl->target_mem_map = NULL;
427
428 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429}
430
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300431static void wl1271_fw_status(struct wl1271 *wl,
432 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200434 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 u32 total = 0;
436 int i;
437
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200438 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439
440 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
441 "drv_rx_counter = %d, tx_results_counter = %d)",
442 status->intr,
443 status->fw_rx_counter,
444 status->drv_rx_counter,
445 status->tx_results_counter);
446
447 /* update number of available TX blocks */
448 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300449 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
450 wl->tx_blocks_freed[i];
451
452 wl->tx_blocks_freed[i] =
453 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454 wl->tx_blocks_available += cnt;
455 total += cnt;
456 }
457
458 /* if more blocks are available now, schedule some tx work */
459 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300460 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
462 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200463 getnstimeofday(&ts);
464 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
465 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466}
467
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200468#define WL1271_IRQ_MAX_LOOPS 10
469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470static void wl1271_irq_work(struct work_struct *work)
471{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300473 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200474 int loopcount = WL1271_IRQ_MAX_LOOPS;
475 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476 struct wl1271 *wl =
477 container_of(work, struct wl1271, irq_work);
478
479 mutex_lock(&wl->mutex);
480
481 wl1271_debug(DEBUG_IRQ, "IRQ work");
482
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200483 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484 goto out;
485
486 ret = wl1271_ps_elp_wakeup(wl, true);
487 if (ret < 0)
488 goto out;
489
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200490 spin_lock_irqsave(&wl->wl_lock, flags);
491 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
492 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
493 spin_unlock_irqrestore(&wl->wl_lock, flags);
494 loopcount--;
495
496 wl1271_fw_status(wl, wl->fw_status);
497 intr = le32_to_cpu(wl->fw_status->intr);
498 if (!intr) {
499 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200500 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200501 continue;
502 }
503
504 intr &= WL1271_INTR_MASK;
505
506 if (intr & WL1271_ACX_INTR_DATA) {
507 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
508
509 /* check for tx results */
510 if (wl->fw_status->tx_results_counter !=
511 (wl->tx_results_count & 0xff))
512 wl1271_tx_complete(wl);
513
514 wl1271_rx(wl, wl->fw_status);
515 }
516
517 if (intr & WL1271_ACX_INTR_EVENT_A) {
518 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
519 wl1271_event_handle(wl, 0);
520 }
521
522 if (intr & WL1271_ACX_INTR_EVENT_B) {
523 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
524 wl1271_event_handle(wl, 1);
525 }
526
527 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
528 wl1271_debug(DEBUG_IRQ,
529 "WL1271_ACX_INTR_INIT_COMPLETE");
530
531 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
532 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
533
534 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535 }
536
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200537 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
538 ieee80211_queue_work(wl->hw, &wl->irq_work);
539 else
540 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
541 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 wl1271_ps_elp_sleep(wl);
544
545out:
546 mutex_unlock(&wl->mutex);
547}
548
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549static int wl1271_fetch_firmware(struct wl1271 *wl)
550{
551 const struct firmware *fw;
552 int ret;
553
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200554 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 if (ret < 0) {
557 wl1271_error("could not get firmware: %d", ret);
558 return ret;
559 }
560
561 if (fw->size % 4) {
562 wl1271_error("firmware size is not multiple of 32 bits: %zu",
563 fw->size);
564 ret = -EILSEQ;
565 goto out;
566 }
567
568 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300569 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570
571 if (!wl->fw) {
572 wl1271_error("could not allocate memory for the firmware");
573 ret = -ENOMEM;
574 goto out;
575 }
576
577 memcpy(wl->fw, fw->data, wl->fw_len);
578
579 ret = 0;
580
581out:
582 release_firmware(fw);
583
584 return ret;
585}
586
587static int wl1271_fetch_nvs(struct wl1271 *wl)
588{
589 const struct firmware *fw;
590 int ret;
591
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200592 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593
594 if (ret < 0) {
595 wl1271_error("could not get nvs file: %d", ret);
596 return ret;
597 }
598
Julia Lawall929ebd32010-05-15 23:16:39 +0200599 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600
601 if (!wl->nvs) {
602 wl1271_error("could not allocate memory for the nvs file");
603 ret = -ENOMEM;
604 goto out;
605 }
606
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200607 wl->nvs_len = fw->size;
608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609out:
610 release_firmware(fw);
611
612 return ret;
613}
614
615static void wl1271_fw_wakeup(struct wl1271 *wl)
616{
617 u32 elp_reg;
618
619 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300620 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621}
622
623static int wl1271_setup(struct wl1271 *wl)
624{
625 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
626 if (!wl->fw_status)
627 return -ENOMEM;
628
629 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
630 if (!wl->tx_res_if) {
631 kfree(wl->fw_status);
632 return -ENOMEM;
633 }
634
635 INIT_WORK(&wl->irq_work, wl1271_irq_work);
636 INIT_WORK(&wl->tx_work, wl1271_tx_work);
Juuso Oikarinenc454f1d2010-08-24 06:28:03 +0300637 INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 return 0;
640}
641
642static int wl1271_chip_wakeup(struct wl1271 *wl)
643{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300644 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645 int ret = 0;
646
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200647 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200648 ret = wl1271_power_on(wl);
649 if (ret < 0)
650 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200652 wl1271_io_reset(wl);
653 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654
655 /* We don't need a real memory partition here, because we only want
656 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300657 memset(&partition, 0, sizeof(partition));
658 partition.reg.start = REGISTERS_BASE;
659 partition.reg.size = REGISTERS_DOWN_SIZE;
660 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661
662 /* ELP module wake up */
663 wl1271_fw_wakeup(wl);
664
665 /* whal_FwCtrl_BootSm() */
666
667 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200668 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669
670 /* 1. check if chip id is valid */
671
672 switch (wl->chip.id) {
673 case CHIP_ID_1271_PG10:
674 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
675 wl->chip.id);
676
677 ret = wl1271_setup(wl);
678 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 break;
681 case CHIP_ID_1271_PG20:
682 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
683 wl->chip.id);
684
685 ret = wl1271_setup(wl);
686 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200687 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 break;
689 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200692 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 }
694
695 if (wl->fw == NULL) {
696 ret = wl1271_fetch_firmware(wl);
697 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200698 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 }
700
701 /* No NVS from netlink, try to get it from the filesystem */
702 if (wl->nvs == NULL) {
703 ret = wl1271_fetch_nvs(wl);
704 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 }
707
708out:
709 return ret;
710}
711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712int wl1271_plt_start(struct wl1271 *wl)
713{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 int ret;
716
717 mutex_lock(&wl->mutex);
718
719 wl1271_notice("power up");
720
721 if (wl->state != WL1271_STATE_OFF) {
722 wl1271_error("cannot go into PLT state because not "
723 "in off state: %d", wl->state);
724 ret = -EBUSY;
725 goto out;
726 }
727
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200728 while (retries) {
729 retries--;
730 ret = wl1271_chip_wakeup(wl);
731 if (ret < 0)
732 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 ret = wl1271_boot(wl);
735 if (ret < 0)
736 goto power_off;
737
738 ret = wl1271_plt_init(wl);
739 if (ret < 0)
740 goto irq_disable;
741
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 wl->state = WL1271_STATE_PLT;
743 wl1271_notice("firmware booted in PLT mode (%s)",
744 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745 goto out;
746
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747irq_disable:
748 wl1271_disable_interrupts(wl);
749 mutex_unlock(&wl->mutex);
750 /* Unlocking the mutex in the middle of handling is
751 inherently unsafe. In this case we deem it safe to do,
752 because we need to let any possibly pending IRQ out of
753 the system (and while we are WL1271_STATE_OFF the IRQ
754 work function will not do anything.) Also, any other
755 possible concurrent operations will fail due to the
756 current state, hence the wl1271 struct should be safe. */
757 cancel_work_sync(&wl->irq_work);
758 mutex_lock(&wl->mutex);
759power_off:
760 wl1271_power_off(wl);
761 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200763 wl1271_error("firmware boot in PLT mode failed despite %d retries",
764 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765out:
766 mutex_unlock(&wl->mutex);
767
768 return ret;
769}
770
771int wl1271_plt_stop(struct wl1271 *wl)
772{
773 int ret = 0;
774
775 mutex_lock(&wl->mutex);
776
777 wl1271_notice("power down");
778
779 if (wl->state != WL1271_STATE_PLT) {
780 wl1271_error("cannot power down because not in PLT "
781 "state: %d", wl->state);
782 ret = -EBUSY;
783 goto out;
784 }
785
786 wl1271_disable_interrupts(wl);
787 wl1271_power_off(wl);
788
789 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300790 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791
792out:
793 mutex_unlock(&wl->mutex);
794
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200795 cancel_work_sync(&wl->irq_work);
796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797 return ret;
798}
799
800
801static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
802{
803 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200804 struct ieee80211_conf *conf = &hw->conf;
805 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
806 struct ieee80211_sta *sta = txinfo->control.sta;
807 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200809 /* peek into the rates configured in the STA entry */
810 spin_lock_irqsave(&wl->wl_lock, flags);
811 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
812 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
813 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
814 }
815 spin_unlock_irqrestore(&wl->wl_lock, flags);
816
817 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818 skb_queue_tail(&wl->tx_queue, skb);
819
820 /*
821 * The chip specific setup must run before the first TX packet -
822 * before that, the tx_work will not be initialized!
823 */
824
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300825 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826
827 /*
828 * The workqueue is slow to process the tx_queue and we need stop
829 * the queue here, otherwise the queue will get too long.
830 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200831 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
832 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200834 spin_lock_irqsave(&wl->wl_lock, flags);
835 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200836 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200837 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838 }
839
840 return NETDEV_TX_OK;
841}
842
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300843static struct notifier_block wl1271_dev_notifier = {
844 .notifier_call = wl1271_dev_notify,
845};
846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847static int wl1271_op_start(struct ieee80211_hw *hw)
848{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200849 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
850
851 /*
852 * We have to delay the booting of the hardware because
853 * we need to know the local MAC address before downloading and
854 * initializing the firmware. The MAC address cannot be changed
855 * after boot, and without the proper MAC address, the firmware
856 * will not function properly.
857 *
858 * The MAC address is first known when the corresponding interface
859 * is added. That is where we will initialize the hardware.
860 */
861
862 return 0;
863}
864
865static void wl1271_op_stop(struct ieee80211_hw *hw)
866{
867 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
868}
869
870static int wl1271_op_add_interface(struct ieee80211_hw *hw,
871 struct ieee80211_vif *vif)
872{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400874 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200875 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876 int ret = 0;
877
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200878 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
879 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880
881 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200882 if (wl->vif) {
883 ret = -EBUSY;
884 goto out;
885 }
886
887 wl->vif = vif;
888
889 switch (vif->type) {
890 case NL80211_IFTYPE_STATION:
891 wl->bss_type = BSS_TYPE_STA_BSS;
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 case NL80211_IFTYPE_ADHOC:
895 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200896 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200897 break;
898 default:
899 ret = -EOPNOTSUPP;
900 goto out;
901 }
902
903 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904
905 if (wl->state != WL1271_STATE_OFF) {
906 wl1271_error("cannot start because not in off state: %d",
907 wl->state);
908 ret = -EBUSY;
909 goto out;
910 }
911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 while (retries) {
913 retries--;
914 ret = wl1271_chip_wakeup(wl);
915 if (ret < 0)
916 goto power_off;
917
918 ret = wl1271_boot(wl);
919 if (ret < 0)
920 goto power_off;
921
922 ret = wl1271_hw_init(wl);
923 if (ret < 0)
924 goto irq_disable;
925
926 wl->state = WL1271_STATE_ON;
927 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400928
929 /* update hw/fw version info in wiphy struct */
930 wiphy->hw_version = wl->chip.id;
931 strncpy(wiphy->fw_version, wl->chip.fw_ver,
932 sizeof(wiphy->fw_version));
933
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 goto out;
935
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200936irq_disable:
937 wl1271_disable_interrupts(wl);
938 mutex_unlock(&wl->mutex);
939 /* Unlocking the mutex in the middle of handling is
940 inherently unsafe. In this case we deem it safe to do,
941 because we need to let any possibly pending IRQ out of
942 the system (and while we are WL1271_STATE_OFF the IRQ
943 work function will not do anything.) Also, any other
944 possible concurrent operations will fail due to the
945 current state, hence the wl1271 struct should be safe. */
946 cancel_work_sync(&wl->irq_work);
947 mutex_lock(&wl->mutex);
948power_off:
949 wl1271_power_off(wl);
950 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200952 wl1271_error("firmware boot failed despite %d retries",
953 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300954out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955 mutex_unlock(&wl->mutex);
956
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300957 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300958 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 return ret;
961}
962
Juuso Oikarinen52a2a372010-09-21 06:23:30 +0200963static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 int i;
966
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200967 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200969 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300971 list_del(&wl->list);
972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 WARN_ON(wl->state != WL1271_STATE_ON);
974
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300975 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300976 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300977 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300978
Luciano Coelho08688d62010-07-08 17:50:07 +0300979 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +0300980 wl->scan.state = WL1271_SCAN_STATE_IDLE;
981 kfree(wl->scan.scanned_ch);
982 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +0300983 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 }
985
986 wl->state = WL1271_STATE_OFF;
987
988 wl1271_disable_interrupts(wl);
989
990 mutex_unlock(&wl->mutex);
991
Juuso Oikarinen52a2a372010-09-21 06:23:30 +0200992 cancel_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 cancel_work_sync(&wl->irq_work);
994 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300995 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200996 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997
998 mutex_lock(&wl->mutex);
999
1000 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001001 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002 wl1271_power_off(wl);
1003
1004 memset(wl->bssid, 0, ETH_ALEN);
1005 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1006 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001008 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001009 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010
1011 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001012 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1014 wl->tx_blocks_available = 0;
1015 wl->tx_results_count = 0;
1016 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001017 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001018 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 wl->time_offset = 0;
1020 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001021 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1022 wl->sta_rate_set = 0;
1023 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001024 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001025 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027 for (i = 0; i < NUM_TX_QUEUES; i++)
1028 wl->tx_blocks_freed[i] = 0;
1029
1030 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001031
1032 kfree(wl->fw_status);
1033 wl->fw_status = NULL;
1034 kfree(wl->tx_res_if);
1035 wl->tx_res_if = NULL;
1036 kfree(wl->target_mem_map);
1037 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001038}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001039
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001040static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1041 struct ieee80211_vif *vif)
1042{
1043 struct wl1271 *wl = hw->priv;
1044
1045 mutex_lock(&wl->mutex);
1046 WARN_ON(wl->vif != vif);
1047 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 mutex_unlock(&wl->mutex);
1049}
1050
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001051static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1052{
1053 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1054 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1055
1056 /* combine requested filters with current filter config */
1057 filters = wl->filters | filters;
1058
1059 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1060
1061 if (filters & FIF_PROMISC_IN_BSS) {
1062 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1063 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1064 wl->rx_config |= CFG_BSSID_FILTER_EN;
1065 }
1066 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1067 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1068 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1069 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1070 }
1071 if (filters & FIF_OTHER_BSS) {
1072 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1073 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1074 }
1075 if (filters & FIF_CONTROL) {
1076 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1077 wl->rx_filter |= CFG_RX_CTL_EN;
1078 }
1079 if (filters & FIF_FCSFAIL) {
1080 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1081 wl->rx_filter |= CFG_RX_FCS_ERROR;
1082 }
1083}
1084
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001085static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001086{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001087 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001088 /* we need to use a dummy BSSID for now */
1089 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1090 0xad, 0xbe, 0xef };
1091
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001092 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1093
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001094 /* pass through frames from all BSS */
1095 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1096
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001097 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001098 if (ret < 0)
1099 goto out;
1100
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001101 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001102
1103out:
1104 return ret;
1105}
1106
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001107static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001108{
1109 int ret;
1110
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001111 /*
1112 * One of the side effects of the JOIN command is that is clears
1113 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1114 * to a WPA/WPA2 access point will therefore kill the data-path.
1115 * Currently there is no supported scenario for JOIN during
1116 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1117 * must be handled somehow.
1118 *
1119 */
1120 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1121 wl1271_info("JOIN while associated.");
1122
1123 if (set_assoc)
1124 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1125
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001126 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1127 if (ret < 0)
1128 goto out;
1129
1130 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1131
1132 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1133 goto out;
1134
1135 /*
1136 * The join command disable the keep-alive mode, shut down its process,
1137 * and also clear the template config, so we need to reset it all after
1138 * the join. The acx_aid starts the keep-alive process, and the order
1139 * of the commands below is relevant.
1140 */
1141 ret = wl1271_acx_keep_alive_mode(wl, true);
1142 if (ret < 0)
1143 goto out;
1144
1145 ret = wl1271_acx_aid(wl, wl->aid);
1146 if (ret < 0)
1147 goto out;
1148
1149 ret = wl1271_cmd_build_klv_null_data(wl);
1150 if (ret < 0)
1151 goto out;
1152
1153 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1154 ACX_KEEP_ALIVE_TPL_VALID);
1155 if (ret < 0)
1156 goto out;
1157
1158out:
1159 return ret;
1160}
1161
1162static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001163{
1164 int ret;
1165
1166 /* to stop listening to a channel, we disconnect */
1167 ret = wl1271_cmd_disconnect(wl);
1168 if (ret < 0)
1169 goto out;
1170
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001171 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001172 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001173
1174 /* stop filterting packets based on bssid */
1175 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001176
1177out:
1178 return ret;
1179}
1180
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001181static void wl1271_set_band_rate(struct wl1271 *wl)
1182{
1183 if (wl->band == IEEE80211_BAND_2GHZ)
1184 wl->basic_rate_set = wl->conf.tx.basic_rate;
1185 else
1186 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1187}
1188
1189static u32 wl1271_min_rate_get(struct wl1271 *wl)
1190{
1191 int i;
1192 u32 rate = 0;
1193
1194 if (!wl->basic_rate_set) {
1195 WARN_ON(1);
1196 wl->basic_rate_set = wl->conf.tx.basic_rate;
1197 }
1198
1199 for (i = 0; !rate; i++) {
1200 if ((wl->basic_rate_set >> i) & 0x1)
1201 rate = 1 << i;
1202 }
1203
1204 return rate;
1205}
1206
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001207static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1208{
1209 int ret;
1210
1211 if (idle) {
1212 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1213 ret = wl1271_unjoin(wl);
1214 if (ret < 0)
1215 goto out;
1216 }
1217 wl->rate_set = wl1271_min_rate_get(wl);
1218 wl->sta_rate_set = 0;
1219 ret = wl1271_acx_rate_policies(wl);
1220 if (ret < 0)
1221 goto out;
1222 ret = wl1271_acx_keep_alive_config(
1223 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1224 ACX_KEEP_ALIVE_TPL_INVALID);
1225 if (ret < 0)
1226 goto out;
1227 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1228 } else {
1229 /* increment the session counter */
1230 wl->session_counter++;
1231 if (wl->session_counter >= SESSION_COUNTER_MAX)
1232 wl->session_counter = 0;
1233 ret = wl1271_dummy_join(wl);
1234 if (ret < 0)
1235 goto out;
1236 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1237 }
1238
1239out:
1240 return ret;
1241}
1242
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1244{
1245 struct wl1271 *wl = hw->priv;
1246 struct ieee80211_conf *conf = &hw->conf;
1247 int channel, ret = 0;
1248
1249 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1250
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001251 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 channel,
1253 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001254 conf->power_level,
1255 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001257 /*
1258 * mac80211 will go to idle nearly immediately after transmitting some
1259 * frames, such as the deauth. To make sure those frames reach the air,
1260 * wait here until the TX queue is fully flushed.
1261 */
1262 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1263 (conf->flags & IEEE80211_CONF_IDLE))
1264 wl1271_tx_flush(wl);
1265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 mutex_lock(&wl->mutex);
1267
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001268 if (unlikely(wl->state == WL1271_STATE_OFF))
1269 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001270
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271 ret = wl1271_ps_elp_wakeup(wl, false);
1272 if (ret < 0)
1273 goto out;
1274
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001275 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001276 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1277 ((wl->band != conf->channel->band) ||
1278 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001279 wl->band = conf->channel->band;
1280 wl->channel = channel;
1281
1282 /*
1283 * FIXME: the mac80211 should really provide a fixed rate
1284 * to use here. for now, just use the smallest possible rate
1285 * for the band as a fixed rate for association frames and
1286 * other control messages.
1287 */
1288 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1289 wl1271_set_band_rate(wl);
1290
1291 wl->basic_rate = wl1271_min_rate_get(wl);
1292 ret = wl1271_acx_rate_policies(wl);
1293 if (ret < 0)
1294 wl1271_warning("rate policy for update channel "
1295 "failed %d", ret);
1296
1297 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001298 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001299 if (ret < 0)
1300 wl1271_warning("cmd join to update channel "
1301 "failed %d", ret);
1302 }
1303 }
1304
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001305 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001306 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1307 if (ret < 0)
1308 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 }
1310
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001311 /*
1312 * if mac80211 changes the PSM mode, make sure the mode is not
1313 * incorrectly changed after the pspoll failure active window.
1314 */
1315 if (changed & IEEE80211_CONF_CHANGE_PS)
1316 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1317
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001318 if (conf->flags & IEEE80211_CONF_PS &&
1319 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1320 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321
1322 /*
1323 * We enter PSM only if we're already associated.
1324 * If we're not, we'll enter it when joining an SSID,
1325 * through the bss_info_changed() hook.
1326 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001327 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001328 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001329 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001330 wl->basic_rate_set, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001331 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001333 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001334 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001336 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001338 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001339 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001340 wl->basic_rate_set, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 }
1342
1343 if (conf->power_level != wl->power_level) {
1344 ret = wl1271_acx_tx_power(wl, conf->power_level);
1345 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001346 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347
1348 wl->power_level = conf->power_level;
1349 }
1350
1351out_sleep:
1352 wl1271_ps_elp_sleep(wl);
1353
1354out:
1355 mutex_unlock(&wl->mutex);
1356
1357 return ret;
1358}
1359
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001360struct wl1271_filter_params {
1361 bool enabled;
1362 int mc_list_length;
1363 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1364};
1365
Jiri Pirko22bedad2010-04-01 21:22:57 +00001366static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1367 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001368{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001369 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001370 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001371 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001372
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001373 if (unlikely(wl->state == WL1271_STATE_OFF))
1374 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001375
Juuso Oikarinen74441132009-10-13 12:47:53 +03001376 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001377 if (!fp) {
1378 wl1271_error("Out of memory setting filters.");
1379 return 0;
1380 }
1381
1382 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001383 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001384 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1385 fp->enabled = false;
1386 } else {
1387 fp->enabled = true;
1388 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001389 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001390 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001391 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001392 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001393 }
1394
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001395 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001396}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001398#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1399 FIF_ALLMULTI | \
1400 FIF_FCSFAIL | \
1401 FIF_BCN_PRBRESP_PROMISC | \
1402 FIF_CONTROL | \
1403 FIF_OTHER_BSS)
1404
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1406 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001407 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001409 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001411 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412
1413 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1414
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001415 mutex_lock(&wl->mutex);
1416
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001417 *total &= WL1271_SUPPORTED_FILTERS;
1418 changed &= WL1271_SUPPORTED_FILTERS;
1419
1420 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001421 goto out;
1422
1423 ret = wl1271_ps_elp_wakeup(wl, false);
1424 if (ret < 0)
1425 goto out;
1426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001428 if (*total & FIF_ALLMULTI)
1429 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1430 else if (fp)
1431 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1432 fp->mc_list,
1433 fp->mc_list_length);
1434 if (ret < 0)
1435 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001437 /* determine, whether supported filter values have changed */
1438 if (changed == 0)
1439 goto out_sleep;
1440
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001441 /* configure filters */
1442 wl->filters = *total;
1443 wl1271_configure_filters(wl, 0);
1444
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001445 /* apply configured filters */
1446 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1447 if (ret < 0)
1448 goto out_sleep;
1449
1450out_sleep:
1451 wl1271_ps_elp_sleep(wl);
1452
1453out:
1454 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001455 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456}
1457
1458static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1459 struct ieee80211_vif *vif,
1460 struct ieee80211_sta *sta,
1461 struct ieee80211_key_conf *key_conf)
1462{
1463 struct wl1271 *wl = hw->priv;
1464 const u8 *addr;
1465 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001466 u32 tx_seq_32 = 0;
1467 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 u8 key_type;
1469
1470 static const u8 bcast_addr[ETH_ALEN] =
1471 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1472
1473 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1474
1475 addr = sta ? sta->addr : bcast_addr;
1476
1477 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1478 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1479 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001480 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481 key_conf->keylen, key_conf->flags);
1482 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1483
1484 if (is_zero_ether_addr(addr)) {
1485 /* We dont support TX only encryption */
1486 ret = -EOPNOTSUPP;
1487 goto out;
1488 }
1489
1490 mutex_lock(&wl->mutex);
1491
1492 ret = wl1271_ps_elp_wakeup(wl, false);
1493 if (ret < 0)
1494 goto out_unlock;
1495
Johannes Berg97359d12010-08-10 09:46:38 +02001496 switch (key_conf->cipher) {
1497 case WLAN_CIPHER_SUITE_WEP40:
1498 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 key_type = KEY_WEP;
1500
1501 key_conf->hw_key_idx = key_conf->keyidx;
1502 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001503 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 key_type = KEY_TKIP;
1505
1506 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001507 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1508 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001510 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 key_type = KEY_AES;
1512
1513 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001514 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1515 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 break;
1517 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001518 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
1520 ret = -EOPNOTSUPP;
1521 goto out_sleep;
1522 }
1523
1524 switch (cmd) {
1525 case SET_KEY:
1526 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1527 key_conf->keyidx, key_type,
1528 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001529 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 if (ret < 0) {
1531 wl1271_error("Could not add or replace key");
1532 goto out_sleep;
1533 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001534
1535 /* the default WEP key needs to be configured at least once */
1536 if (key_type == KEY_WEP) {
1537 ret = wl1271_cmd_set_default_wep_key(wl,
1538 wl->default_key);
1539 if (ret < 0)
1540 goto out_sleep;
1541 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542 break;
1543
1544 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001545 /* The wl1271 does not allow to remove unicast keys - they
1546 will be cleared automatically on next CMD_JOIN. Ignore the
1547 request silently, as we dont want the mac80211 to emit
1548 an error message. */
1549 if (!is_broadcast_ether_addr(addr))
1550 break;
1551
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1553 key_conf->keyidx, key_type,
1554 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001555 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556 if (ret < 0) {
1557 wl1271_error("Could not remove key");
1558 goto out_sleep;
1559 }
1560 break;
1561
1562 default:
1563 wl1271_error("Unsupported key cmd 0x%x", cmd);
1564 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565 break;
1566 }
1567
1568out_sleep:
1569 wl1271_ps_elp_sleep(wl);
1570
1571out_unlock:
1572 mutex_unlock(&wl->mutex);
1573
1574out:
1575 return ret;
1576}
1577
1578static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001579 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 struct cfg80211_scan_request *req)
1581{
1582 struct wl1271 *wl = hw->priv;
1583 int ret;
1584 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001585 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586
1587 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1588
1589 if (req->n_ssids) {
1590 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001591 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 }
1593
1594 mutex_lock(&wl->mutex);
1595
1596 ret = wl1271_ps_elp_wakeup(wl, false);
1597 if (ret < 0)
1598 goto out;
1599
Luciano Coelho5924f892010-08-04 03:46:22 +03001600 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601
1602 wl1271_ps_elp_sleep(wl);
1603
1604out:
1605 mutex_unlock(&wl->mutex);
1606
1607 return ret;
1608}
1609
1610static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1611{
1612 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001613 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614
1615 mutex_lock(&wl->mutex);
1616
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001617 if (unlikely(wl->state == WL1271_STATE_OFF))
1618 goto out;
1619
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 ret = wl1271_ps_elp_wakeup(wl, false);
1621 if (ret < 0)
1622 goto out;
1623
1624 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1625 if (ret < 0)
1626 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1627
1628 wl1271_ps_elp_sleep(wl);
1629
1630out:
1631 mutex_unlock(&wl->mutex);
1632
1633 return ret;
1634}
1635
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001636static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1637{
1638 u8 *ptr = beacon->data +
1639 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1640
1641 /* find the location of the ssid in the beacon */
1642 while (ptr < beacon->data + beacon->len) {
1643 if (ptr[0] == WLAN_EID_SSID) {
1644 wl->ssid_len = ptr[1];
1645 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1646 return;
1647 }
1648 ptr += ptr[1];
1649 }
1650 wl1271_error("ad-hoc beacon template has no SSID!\n");
1651}
1652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1654 struct ieee80211_vif *vif,
1655 struct ieee80211_bss_conf *bss_conf,
1656 u32 changed)
1657{
1658 enum wl1271_cmd_ps_mode mode;
1659 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001660 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001661 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 int ret;
1663
1664 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1665
1666 mutex_lock(&wl->mutex);
1667
1668 ret = wl1271_ps_elp_wakeup(wl, false);
1669 if (ret < 0)
1670 goto out;
1671
Eliad Peller9ee82d52010-09-19 18:55:09 +02001672 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001673 (wl->bss_type == BSS_TYPE_IBSS)) {
1674 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1675 bss_conf->beacon_int);
1676
1677 wl->beacon_int = bss_conf->beacon_int;
1678 do_join = true;
1679 }
1680
Eliad Peller9ee82d52010-09-19 18:55:09 +02001681 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001682 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1684
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001685 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1686
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001687 if (beacon) {
1688 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001689
1690 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001691 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1692 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001693 beacon->len, 0,
1694 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001695
1696 if (ret < 0) {
1697 dev_kfree_skb(beacon);
1698 goto out_sleep;
1699 }
1700
1701 hdr = (struct ieee80211_hdr *) beacon->data;
1702 hdr->frame_control = cpu_to_le16(
1703 IEEE80211_FTYPE_MGMT |
1704 IEEE80211_STYPE_PROBE_RESP);
1705
1706 ret = wl1271_cmd_template_set(wl,
1707 CMD_TEMPL_PROBE_RESPONSE,
1708 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001709 beacon->len, 0,
1710 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001711 dev_kfree_skb(beacon);
1712 if (ret < 0)
1713 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001714
1715 /* Need to update the SSID (for filtering etc) */
1716 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001717 }
1718 }
1719
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001720 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1721 (wl->bss_type == BSS_TYPE_IBSS)) {
1722 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1723 bss_conf->enable_beacon ? "enabled" : "disabled");
1724
1725 if (bss_conf->enable_beacon)
1726 wl->set_bss_type = BSS_TYPE_IBSS;
1727 else
1728 wl->set_bss_type = BSS_TYPE_STA_BSS;
1729 do_join = true;
1730 }
1731
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001732 if (changed & BSS_CHANGED_CQM) {
1733 bool enable = false;
1734 if (bss_conf->cqm_rssi_thold)
1735 enable = true;
1736 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1737 bss_conf->cqm_rssi_thold,
1738 bss_conf->cqm_rssi_hyst);
1739 if (ret < 0)
1740 goto out;
1741 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1742 }
1743
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001744 if ((changed & BSS_CHANGED_BSSID) &&
1745 /*
1746 * Now we know the correct bssid, so we send a new join command
1747 * and enable the BSSID filter
1748 */
1749 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001750 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001751
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001752 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001753 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001754 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001755
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001756 ret = wl1271_build_qos_null_data(wl);
1757 if (ret < 0)
1758 goto out_sleep;
1759
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001760 /* filter out all packets not from this BSSID */
1761 wl1271_configure_filters(wl, 0);
1762
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001763 /* Need to update the BSSID (for filtering etc) */
1764 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001765 }
1766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 if (changed & BSS_CHANGED_ASSOC) {
1768 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001769 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001771 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001773 wl->ps_poll_failures = 0;
1774
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001775 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001776 * use basic rates from AP, and determine lowest rate
1777 * to use with control frames.
1778 */
1779 rates = bss_conf->basic_rates;
1780 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1781 rates);
1782 wl->basic_rate = wl1271_min_rate_get(wl);
1783 ret = wl1271_acx_rate_policies(wl);
1784 if (ret < 0)
1785 goto out_sleep;
1786
1787 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001788 * with wl1271, we don't need to update the
1789 * beacon_int and dtim_period, because the firmware
1790 * updates it by itself when the first beacon is
1791 * received after a join.
1792 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1794 if (ret < 0)
1795 goto out_sleep;
1796
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001797 /*
1798 * The SSID is intentionally set to NULL here - the
1799 * firmware will set the probe request with a
1800 * broadcast SSID regardless of what we set in the
1801 * template.
1802 */
1803 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1804 NULL, 0, wl->band);
1805
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001806 /* enable the connection monitoring feature */
1807 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 if (ret < 0)
1809 goto out_sleep;
1810
1811 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001812 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1813 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001815 ret = wl1271_ps_set_mode(wl, mode,
1816 wl->basic_rate_set,
1817 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 if (ret < 0)
1819 goto out_sleep;
1820 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001821 } else {
1822 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001823 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001824 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001825 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001826
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001827 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001828 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001829
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001830 /* revert back to minimum rates for the current band */
1831 wl1271_set_band_rate(wl);
1832 wl->basic_rate = wl1271_min_rate_get(wl);
1833 ret = wl1271_acx_rate_policies(wl);
1834 if (ret < 0)
1835 goto out_sleep;
1836
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001837 /* disable connection monitor features */
1838 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001839
1840 /* Disable the keep-alive feature */
1841 ret = wl1271_acx_keep_alive_mode(wl, false);
1842
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001843 if (ret < 0)
1844 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001845 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 if (changed & BSS_CHANGED_ERP_SLOT) {
1850 if (bss_conf->use_short_slot)
1851 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1852 else
1853 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1854 if (ret < 0) {
1855 wl1271_warning("Set slot time failed %d", ret);
1856 goto out_sleep;
1857 }
1858 }
1859
1860 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1861 if (bss_conf->use_short_preamble)
1862 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1863 else
1864 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1865 }
1866
1867 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1868 if (bss_conf->use_cts_prot)
1869 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1870 else
1871 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1872 if (ret < 0) {
1873 wl1271_warning("Set ctsprotect failed %d", ret);
1874 goto out_sleep;
1875 }
1876 }
1877
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001878 if (changed & BSS_CHANGED_ARP_FILTER) {
1879 __be32 addr = bss_conf->arp_addr_list[0];
1880 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1881
1882 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1883 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1884 else
1885 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1886
1887 if (ret < 0)
1888 goto out_sleep;
1889 }
1890
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001891 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001892 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001893 if (ret < 0) {
1894 wl1271_warning("cmd join failed %d", ret);
1895 goto out_sleep;
1896 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001897 }
1898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001899out_sleep:
1900 wl1271_ps_elp_sleep(wl);
1901
1902out:
1903 mutex_unlock(&wl->mutex);
1904}
1905
Kalle Valoc6999d82010-02-18 13:25:41 +02001906static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1907 const struct ieee80211_tx_queue_params *params)
1908{
1909 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001910 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001911 int ret;
1912
1913 mutex_lock(&wl->mutex);
1914
1915 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1916
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001917 ret = wl1271_ps_elp_wakeup(wl, false);
1918 if (ret < 0)
1919 goto out;
1920
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001921 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001922 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1923 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001924 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001925 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001926 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001927
Kalle Valo4695dc92010-03-18 12:26:38 +02001928 if (params->uapsd)
1929 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1930 else
1931 ps_scheme = CONF_PS_SCHEME_LEGACY;
1932
Kalle Valoc6999d82010-02-18 13:25:41 +02001933 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1934 CONF_CHANNEL_TYPE_EDCF,
1935 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001936 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001937 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001938 goto out_sleep;
1939
1940out_sleep:
1941 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001942
1943out:
1944 mutex_unlock(&wl->mutex);
1945
1946 return ret;
1947}
1948
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001949static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1950{
1951
1952 struct wl1271 *wl = hw->priv;
1953 u64 mactime = ULLONG_MAX;
1954 int ret;
1955
1956 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1957
1958 mutex_lock(&wl->mutex);
1959
1960 ret = wl1271_ps_elp_wakeup(wl, false);
1961 if (ret < 0)
1962 goto out;
1963
1964 ret = wl1271_acx_tsf_info(wl, &mactime);
1965 if (ret < 0)
1966 goto out_sleep;
1967
1968out_sleep:
1969 wl1271_ps_elp_sleep(wl);
1970
1971out:
1972 mutex_unlock(&wl->mutex);
1973 return mactime;
1974}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
John W. Linvilleece550d2010-07-28 16:41:06 -04001976static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
1977 struct survey_info *survey)
1978{
1979 struct wl1271 *wl = hw->priv;
1980 struct ieee80211_conf *conf = &hw->conf;
1981
1982 if (idx != 0)
1983 return -ENOENT;
1984
1985 survey->channel = conf->channel;
1986 survey->filled = SURVEY_INFO_NOISE_DBM;
1987 survey->noise = wl->noise;
1988
1989 return 0;
1990}
1991
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992/* can't be const, mac80211 writes to this */
1993static struct ieee80211_rate wl1271_rates[] = {
1994 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001995 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1996 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001998 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1999 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2001 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002002 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2003 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2005 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002006 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2007 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2009 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002010 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2011 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002013 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2014 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002016 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2017 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002019 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2020 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002022 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2023 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002025 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2026 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002028 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2029 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002031 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2032 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033};
2034
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002035/*
2036 * Can't be const, mac80211 writes to this. The order of the channels here
2037 * is designed to improve scanning.
2038 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002040 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002041 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002042 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002043 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002044 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2045 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2046 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2047 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2048 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2049 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2050 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2051 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2052 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053};
2054
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002055/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002056static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002057 /* MCS rates are used only with 11n */
2058 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2059 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2060 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2061 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2062 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2063 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2064 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2065 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2066
2067 11, /* CONF_HW_RXTX_RATE_54 */
2068 10, /* CONF_HW_RXTX_RATE_48 */
2069 9, /* CONF_HW_RXTX_RATE_36 */
2070 8, /* CONF_HW_RXTX_RATE_24 */
2071
2072 /* TI-specific rate */
2073 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2074
2075 7, /* CONF_HW_RXTX_RATE_18 */
2076 6, /* CONF_HW_RXTX_RATE_12 */
2077 3, /* CONF_HW_RXTX_RATE_11 */
2078 5, /* CONF_HW_RXTX_RATE_9 */
2079 4, /* CONF_HW_RXTX_RATE_6 */
2080 2, /* CONF_HW_RXTX_RATE_5_5 */
2081 1, /* CONF_HW_RXTX_RATE_2 */
2082 0 /* CONF_HW_RXTX_RATE_1 */
2083};
2084
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085/* can't be const, mac80211 writes to this */
2086static struct ieee80211_supported_band wl1271_band_2ghz = {
2087 .channels = wl1271_channels,
2088 .n_channels = ARRAY_SIZE(wl1271_channels),
2089 .bitrates = wl1271_rates,
2090 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2091};
2092
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002093/* 5 GHz data rates for WL1273 */
2094static struct ieee80211_rate wl1271_rates_5ghz[] = {
2095 { .bitrate = 60,
2096 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2097 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2098 { .bitrate = 90,
2099 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2100 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2101 { .bitrate = 120,
2102 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2103 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2104 { .bitrate = 180,
2105 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2106 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2107 { .bitrate = 240,
2108 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2109 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2110 { .bitrate = 360,
2111 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2112 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2113 { .bitrate = 480,
2114 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2115 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2116 { .bitrate = 540,
2117 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2118 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2119};
2120
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002121/*
2122 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2123 * The order of the channels here is designed to improve scanning.
2124 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002125static struct ieee80211_channel wl1271_channels_5ghz[] = {
2126 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002127 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002128 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002129 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002130 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002131 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002132 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002133 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002134 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002135 { .hw_value = 184, .center_freq = 4920},
2136 { .hw_value = 189, .center_freq = 4945},
2137 { .hw_value = 9, .center_freq = 5045},
2138 { .hw_value = 36, .center_freq = 5180},
2139 { .hw_value = 46, .center_freq = 5230},
2140 { .hw_value = 64, .center_freq = 5320},
2141 { .hw_value = 116, .center_freq = 5580},
2142 { .hw_value = 136, .center_freq = 5680},
2143 { .hw_value = 192, .center_freq = 4960},
2144 { .hw_value = 11, .center_freq = 5055},
2145 { .hw_value = 38, .center_freq = 5190},
2146 { .hw_value = 48, .center_freq = 5240},
2147 { .hw_value = 100, .center_freq = 5500},
2148 { .hw_value = 120, .center_freq = 5600},
2149 { .hw_value = 140, .center_freq = 5700},
2150 { .hw_value = 185, .center_freq = 4925},
2151 { .hw_value = 196, .center_freq = 4980},
2152 { .hw_value = 12, .center_freq = 5060},
2153 { .hw_value = 40, .center_freq = 5200},
2154 { .hw_value = 52, .center_freq = 5260},
2155 { .hw_value = 104, .center_freq = 5520},
2156 { .hw_value = 124, .center_freq = 5620},
2157 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002158 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002159 { .hw_value = 187, .center_freq = 4935},
2160 { .hw_value = 7, .center_freq = 5035},
2161 { .hw_value = 16, .center_freq = 5080},
2162 { .hw_value = 42, .center_freq = 5210},
2163 { .hw_value = 56, .center_freq = 5280},
2164 { .hw_value = 108, .center_freq = 5540},
2165 { .hw_value = 128, .center_freq = 5640},
2166 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002167 { .hw_value = 165, .center_freq = 5825},
2168};
2169
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002170/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002171static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002172 /* MCS rates are used only with 11n */
2173 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2174 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2175 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2176 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2177 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2178 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2179 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2180 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2181
2182 7, /* CONF_HW_RXTX_RATE_54 */
2183 6, /* CONF_HW_RXTX_RATE_48 */
2184 5, /* CONF_HW_RXTX_RATE_36 */
2185 4, /* CONF_HW_RXTX_RATE_24 */
2186
2187 /* TI-specific rate */
2188 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2189
2190 3, /* CONF_HW_RXTX_RATE_18 */
2191 2, /* CONF_HW_RXTX_RATE_12 */
2192 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2193 1, /* CONF_HW_RXTX_RATE_9 */
2194 0, /* CONF_HW_RXTX_RATE_6 */
2195 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2196 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2197 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2198};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002199
2200static struct ieee80211_supported_band wl1271_band_5ghz = {
2201 .channels = wl1271_channels_5ghz,
2202 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2203 .bitrates = wl1271_rates_5ghz,
2204 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2205};
2206
Tobias Klausera0ea9492010-05-20 10:38:11 +02002207static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002208 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2209 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2210};
2211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002212static const struct ieee80211_ops wl1271_ops = {
2213 .start = wl1271_op_start,
2214 .stop = wl1271_op_stop,
2215 .add_interface = wl1271_op_add_interface,
2216 .remove_interface = wl1271_op_remove_interface,
2217 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002218 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219 .configure_filter = wl1271_op_configure_filter,
2220 .tx = wl1271_op_tx,
2221 .set_key = wl1271_op_set_key,
2222 .hw_scan = wl1271_op_hw_scan,
2223 .bss_info_changed = wl1271_op_bss_info_changed,
2224 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002225 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002226 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002227 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002228 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002229};
2230
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002231
2232u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2233{
2234 u8 idx;
2235
2236 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2237
2238 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2239 wl1271_error("Illegal RX rate from HW: %d", rate);
2240 return 0;
2241 }
2242
2243 idx = wl1271_band_rate_to_idx[wl->band][rate];
2244 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2245 wl1271_error("Unsupported RX rate from HW: %d", rate);
2246 return 0;
2247 }
2248
2249 return idx;
2250}
2251
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002252static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2253 struct device_attribute *attr,
2254 char *buf)
2255{
2256 struct wl1271 *wl = dev_get_drvdata(dev);
2257 ssize_t len;
2258
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002259 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002260
2261 mutex_lock(&wl->mutex);
2262 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2263 wl->sg_enabled);
2264 mutex_unlock(&wl->mutex);
2265
2266 return len;
2267
2268}
2269
2270static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2271 struct device_attribute *attr,
2272 const char *buf, size_t count)
2273{
2274 struct wl1271 *wl = dev_get_drvdata(dev);
2275 unsigned long res;
2276 int ret;
2277
2278 ret = strict_strtoul(buf, 10, &res);
2279
2280 if (ret < 0) {
2281 wl1271_warning("incorrect value written to bt_coex_mode");
2282 return count;
2283 }
2284
2285 mutex_lock(&wl->mutex);
2286
2287 res = !!res;
2288
2289 if (res == wl->sg_enabled)
2290 goto out;
2291
2292 wl->sg_enabled = res;
2293
2294 if (wl->state == WL1271_STATE_OFF)
2295 goto out;
2296
2297 ret = wl1271_ps_elp_wakeup(wl, false);
2298 if (ret < 0)
2299 goto out;
2300
2301 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2302 wl1271_ps_elp_sleep(wl);
2303
2304 out:
2305 mutex_unlock(&wl->mutex);
2306 return count;
2307}
2308
2309static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2310 wl1271_sysfs_show_bt_coex_state,
2311 wl1271_sysfs_store_bt_coex_state);
2312
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002313static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2314 struct device_attribute *attr,
2315 char *buf)
2316{
2317 struct wl1271 *wl = dev_get_drvdata(dev);
2318 ssize_t len;
2319
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002320 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002321
2322 mutex_lock(&wl->mutex);
2323 if (wl->hw_pg_ver >= 0)
2324 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2325 else
2326 len = snprintf(buf, len, "n/a\n");
2327 mutex_unlock(&wl->mutex);
2328
2329 return len;
2330}
2331
2332static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2333 wl1271_sysfs_show_hw_pg_ver, NULL);
2334
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002335int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336{
2337 int ret;
2338
2339 if (wl->mac80211_registered)
2340 return 0;
2341
2342 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2343
2344 ret = ieee80211_register_hw(wl->hw);
2345 if (ret < 0) {
2346 wl1271_error("unable to register mac80211 hw: %d", ret);
2347 return ret;
2348 }
2349
2350 wl->mac80211_registered = true;
2351
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002352 register_netdevice_notifier(&wl1271_dev_notifier);
2353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002354 wl1271_notice("loaded");
2355
2356 return 0;
2357}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002358EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002359
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002360void wl1271_unregister_hw(struct wl1271 *wl)
2361{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002362 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002363 ieee80211_unregister_hw(wl->hw);
2364 wl->mac80211_registered = false;
2365
2366}
2367EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2368
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002369int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002371 /* The tx descriptor buffer and the TKIP space. */
2372 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2373 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374
2375 /* unit us */
2376 /* FIXME: find a proper value */
2377 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002378 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379
2380 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002381 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002382 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002383 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002384 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002385 IEEE80211_HW_CONNECTION_MONITOR |
2386 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002388 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2389 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 wl->hw->wiphy->max_scan_ssids = 1;
2391 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002392 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002393
Kalle Valo12bd8942010-03-18 12:26:33 +02002394 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002395 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002396
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002397 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398
2399 return 0;
2400}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002401EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002404
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002405struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002406{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002407 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002408 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002410 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002411
2412 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2413 if (!hw) {
2414 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002415 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002416 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002417 }
2418
Julia Lawall929ebd32010-05-15 23:16:39 +02002419 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002420 if (!plat_dev) {
2421 wl1271_error("could not allocate platform_device");
2422 ret = -ENOMEM;
2423 goto err_plat_alloc;
2424 }
2425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002426 wl = hw->priv;
2427 memset(wl, 0, sizeof(*wl));
2428
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002429 INIT_LIST_HEAD(&wl->list);
2430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002431 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002432 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433
2434 skb_queue_head_init(&wl->tx_queue);
2435
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002436 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002437 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002438 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002439 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002441 wl->rx_counter = 0;
2442 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2443 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002444 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002446 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002447 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002448 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2449 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002450 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002451 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002452 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002453 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002454 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002456 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457 wl->tx_frames[i] = NULL;
2458
2459 spin_lock_init(&wl->wl_lock);
2460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461 wl->state = WL1271_STATE_OFF;
2462 mutex_init(&wl->mutex);
2463
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002464 /* Apply default driver configuration. */
2465 wl1271_conf_init(wl);
2466
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002467 wl1271_debugfs_init(wl);
2468
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002469 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002470 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002471 if (ret) {
2472 wl1271_error("couldn't register platform device");
2473 goto err_hw;
2474 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002475 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002476
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002477 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002478 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002479 if (ret < 0) {
2480 wl1271_error("failed to create sysfs file bt_coex_state");
2481 goto err_platform;
2482 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002483
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002484 /* Create sysfs file to get HW PG version */
2485 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2486 if (ret < 0) {
2487 wl1271_error("failed to create sysfs file hw_pg_ver");
2488 goto err_bt_coex_state;
2489 }
2490
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002491 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002492
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002493err_bt_coex_state:
2494 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2495
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002496err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002497 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002498
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002499err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002500 wl1271_debugfs_exit(wl);
2501 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002502
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002503err_plat_alloc:
2504 ieee80211_free_hw(hw);
2505
2506err_hw_alloc:
2507
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002508 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002509}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002510EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002511
2512int wl1271_free_hw(struct wl1271 *wl)
2513{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002514 platform_device_unregister(wl->plat_dev);
2515 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002516
2517 wl1271_debugfs_exit(wl);
2518
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002519 vfree(wl->fw);
2520 wl->fw = NULL;
2521 kfree(wl->nvs);
2522 wl->nvs = NULL;
2523
2524 kfree(wl->fw_status);
2525 kfree(wl->tx_res_if);
2526
2527 ieee80211_free_hw(wl->hw);
2528
2529 return 0;
2530}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002531EXPORT_SYMBOL_GPL(wl1271_free_hw);
2532
2533MODULE_LICENSE("GPL");
2534MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2535MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");