blob: 45d4ce36343c21dd167b64bc7995c62efe08b2b7 [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 = {
127 [0] = {
128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
134 [1] = {
135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
141 [2] = {
142 .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 },
148 [3] = {
149 .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 },
156 .tid_conf_count = 7,
157 .tid_conf = {
158 [0] = {
159 .queue_id = 0,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .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 },
166 [1] = {
167 .queue_id = 1,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
174 [2] = {
175 .queue_id = 2,
176 .channel_type = CONF_CHANNEL_TYPE_DCF,
177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
182 [3] = {
183 .queue_id = 3,
184 .channel_type = CONF_CHANNEL_TYPE_DCF,
185 .tsid = CONF_TX_AC_BE,
186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
190 [4] = {
191 .queue_id = 4,
192 .channel_type = CONF_CHANNEL_TYPE_DCF,
193 .tsid = CONF_TX_AC_BE,
194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
198 [5] = {
199 .queue_id = 5,
200 .channel_type = CONF_CHANNEL_TYPE_DCF,
201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
206 [6] = {
207 .queue_id = 6,
208 .channel_type = CONF_CHANNEL_TYPE_DCF,
209 .tsid = CONF_TX_AC_BE,
210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 }
214 },
215 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200216 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300217 .tx_compl_threshold = 4,
218 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
219 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300224 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
225 .bcn_filt_ie_count = 1,
226 .bcn_filt_ie = {
227 [0] = {
228 .ie = WLAN_EID_CHANNEL_SWITCH,
229 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
230 }
231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200240 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200241 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
254 /* FIXME: due to firmware bug, must use value 1 for now */
255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
259 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 }
261};
262
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200263static void wl1271_device_release(struct device *dev)
264{
265
266}
267
268static struct platform_device wl1271_device = {
269 .name = "wl1271",
270 .id = -1,
271
272 /* device model insists to have a release function */
273 .dev = {
274 .release = wl1271_device_release,
275 },
276};
277
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300278static LIST_HEAD(wl_list);
279
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300280static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
281 void *arg)
282{
283 struct net_device *dev = arg;
284 struct wireless_dev *wdev;
285 struct wiphy *wiphy;
286 struct ieee80211_hw *hw;
287 struct wl1271 *wl;
288 struct wl1271 *wl_temp;
289 int ret = 0;
290
291 /* Check that this notification is for us. */
292 if (what != NETDEV_CHANGE)
293 return NOTIFY_DONE;
294
295 wdev = dev->ieee80211_ptr;
296 if (wdev == NULL)
297 return NOTIFY_DONE;
298
299 wiphy = wdev->wiphy;
300 if (wiphy == NULL)
301 return NOTIFY_DONE;
302
303 hw = wiphy_priv(wiphy);
304 if (hw == NULL)
305 return NOTIFY_DONE;
306
307 wl_temp = hw->priv;
308 list_for_each_entry(wl, &wl_list, list) {
309 if (wl == wl_temp)
310 break;
311 }
312 if (wl != wl_temp)
313 return NOTIFY_DONE;
314
315 mutex_lock(&wl->mutex);
316
317 if (wl->state == WL1271_STATE_OFF)
318 goto out;
319
320 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
321 goto out;
322
323 ret = wl1271_ps_elp_wakeup(wl, false);
324 if (ret < 0)
325 goto out;
326
327 if ((dev->operstate == IF_OPER_UP) &&
328 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
329 wl1271_cmd_set_sta_state(wl);
330 wl1271_info("Association completed.");
331 }
332
333 wl1271_ps_elp_sleep(wl);
334
335out:
336 mutex_unlock(&wl->mutex);
337
338 return NOTIFY_OK;
339}
340
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300341static void wl1271_conf_init(struct wl1271 *wl)
342{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300343
344 /*
345 * This function applies the default configuration to the driver. This
346 * function is invoked upon driver load (spi probe.)
347 *
348 * The configuration is stored in a run-time structure in order to
349 * facilitate for run-time adjustment of any of the parameters. Making
350 * changes to the configuration structure will apply the new values on
351 * the next interface up (wl1271_op_start.)
352 */
353
354 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300355 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300356}
357
358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300359static int wl1271_plt_init(struct wl1271 *wl)
360{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200361 struct conf_tx_ac_category *conf_ac;
362 struct conf_tx_tid *conf_tid;
363 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300364
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200365 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200366 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200367 return ret;
368
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200369 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200370 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200371 return ret;
372
Luciano Coelho12419cc2010-02-18 13:25:44 +0200373 ret = wl1271_init_templates_config(wl);
374 if (ret < 0)
375 return ret;
376
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300377 ret = wl1271_acx_init_mem_config(wl);
378 if (ret < 0)
379 return ret;
380
Luciano Coelho12419cc2010-02-18 13:25:44 +0200381 /* PHY layer config */
382 ret = wl1271_init_phy_config(wl);
383 if (ret < 0)
384 goto out_free_memmap;
385
386 ret = wl1271_acx_dco_itrim_params(wl);
387 if (ret < 0)
388 goto out_free_memmap;
389
390 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200391 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200392 if (ret < 0)
393 goto out_free_memmap;
394
395 /* Bluetooth WLAN coexistence */
396 ret = wl1271_init_pta(wl);
397 if (ret < 0)
398 goto out_free_memmap;
399
400 /* Energy detection */
401 ret = wl1271_init_energy_detection(wl);
402 if (ret < 0)
403 goto out_free_memmap;
404
405 /* Default fragmentation threshold */
406 ret = wl1271_acx_frag_threshold(wl);
407 if (ret < 0)
408 goto out_free_memmap;
409
410 /* Default TID configuration */
411 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
412 conf_tid = &wl->conf.tx.tid_conf[i];
413 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
414 conf_tid->channel_type,
415 conf_tid->tsid,
416 conf_tid->ps_scheme,
417 conf_tid->ack_policy,
418 conf_tid->apsd_conf[0],
419 conf_tid->apsd_conf[1]);
420 if (ret < 0)
421 goto out_free_memmap;
422 }
423
424 /* Default AC configuration */
425 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
426 conf_ac = &wl->conf.tx.ac_conf[i];
427 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
428 conf_ac->cw_max, conf_ac->aifsn,
429 conf_ac->tx_op_limit);
430 if (ret < 0)
431 goto out_free_memmap;
432 }
433
434 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200435 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 goto out_free_memmap;
438
439 /* Configure for CAM power saving (ie. always active) */
440 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
441 if (ret < 0)
442 goto out_free_memmap;
443
444 /* configure PM */
445 ret = wl1271_acx_pm_config(wl);
446 if (ret < 0)
447 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300448
449 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200450
451 out_free_memmap:
452 kfree(wl->target_mem_map);
453 wl->target_mem_map = NULL;
454
455 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456}
457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458static void wl1271_fw_status(struct wl1271 *wl,
459 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200461 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462 u32 total = 0;
463 int i;
464
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200465 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466
467 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
468 "drv_rx_counter = %d, tx_results_counter = %d)",
469 status->intr,
470 status->fw_rx_counter,
471 status->drv_rx_counter,
472 status->tx_results_counter);
473
474 /* update number of available TX blocks */
475 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300476 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
477 wl->tx_blocks_freed[i];
478
479 wl->tx_blocks_freed[i] =
480 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481 wl->tx_blocks_available += cnt;
482 total += cnt;
483 }
484
485 /* if more blocks are available now, schedule some tx work */
486 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300487 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488
489 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200490 getnstimeofday(&ts);
491 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
492 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493}
494
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200495#define WL1271_IRQ_MAX_LOOPS 10
496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300497static void wl1271_irq_work(struct work_struct *work)
498{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300500 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200501 int loopcount = WL1271_IRQ_MAX_LOOPS;
502 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300503 struct wl1271 *wl =
504 container_of(work, struct wl1271, irq_work);
505
506 mutex_lock(&wl->mutex);
507
508 wl1271_debug(DEBUG_IRQ, "IRQ work");
509
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200510 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511 goto out;
512
513 ret = wl1271_ps_elp_wakeup(wl, true);
514 if (ret < 0)
515 goto out;
516
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200517 spin_lock_irqsave(&wl->wl_lock, flags);
518 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
519 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
520 spin_unlock_irqrestore(&wl->wl_lock, flags);
521 loopcount--;
522
523 wl1271_fw_status(wl, wl->fw_status);
524 intr = le32_to_cpu(wl->fw_status->intr);
525 if (!intr) {
526 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200527 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200528 continue;
529 }
530
531 intr &= WL1271_INTR_MASK;
532
533 if (intr & WL1271_ACX_INTR_DATA) {
534 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
535
536 /* check for tx results */
537 if (wl->fw_status->tx_results_counter !=
538 (wl->tx_results_count & 0xff))
539 wl1271_tx_complete(wl);
540
541 wl1271_rx(wl, wl->fw_status);
542 }
543
544 if (intr & WL1271_ACX_INTR_EVENT_A) {
545 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
546 wl1271_event_handle(wl, 0);
547 }
548
549 if (intr & WL1271_ACX_INTR_EVENT_B) {
550 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
551 wl1271_event_handle(wl, 1);
552 }
553
554 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
555 wl1271_debug(DEBUG_IRQ,
556 "WL1271_ACX_INTR_INIT_COMPLETE");
557
558 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
559 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
560
561 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 }
563
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200564 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
565 ieee80211_queue_work(wl->hw, &wl->irq_work);
566 else
567 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
568 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570 wl1271_ps_elp_sleep(wl);
571
572out:
573 mutex_unlock(&wl->mutex);
574}
575
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300576static int wl1271_fetch_firmware(struct wl1271 *wl)
577{
578 const struct firmware *fw;
579 int ret;
580
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200581 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300582
583 if (ret < 0) {
584 wl1271_error("could not get firmware: %d", ret);
585 return ret;
586 }
587
588 if (fw->size % 4) {
589 wl1271_error("firmware size is not multiple of 32 bits: %zu",
590 fw->size);
591 ret = -EILSEQ;
592 goto out;
593 }
594
595 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300596 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597
598 if (!wl->fw) {
599 wl1271_error("could not allocate memory for the firmware");
600 ret = -ENOMEM;
601 goto out;
602 }
603
604 memcpy(wl->fw, fw->data, wl->fw_len);
605
606 ret = 0;
607
608out:
609 release_firmware(fw);
610
611 return ret;
612}
613
614static int wl1271_fetch_nvs(struct wl1271 *wl)
615{
616 const struct firmware *fw;
617 int ret;
618
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200619 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620
621 if (ret < 0) {
622 wl1271_error("could not get nvs file: %d", ret);
623 return ret;
624 }
625
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300626 /*
627 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
628 * configurations) can be removed when those NVS files stop floating
629 * around.
630 */
631 if (fw->size != sizeof(struct wl1271_nvs_file) &&
632 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
633 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200634 wl1271_error("nvs size is not as expected: %zu != %zu",
635 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636 ret = -EILSEQ;
637 goto out;
638 }
639
Julia Lawall929ebd32010-05-15 23:16:39 +0200640 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641
642 if (!wl->nvs) {
643 wl1271_error("could not allocate memory for the nvs file");
644 ret = -ENOMEM;
645 goto out;
646 }
647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648out:
649 release_firmware(fw);
650
651 return ret;
652}
653
654static void wl1271_fw_wakeup(struct wl1271 *wl)
655{
656 u32 elp_reg;
657
658 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300659 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660}
661
662static int wl1271_setup(struct wl1271 *wl)
663{
664 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
665 if (!wl->fw_status)
666 return -ENOMEM;
667
668 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
669 if (!wl->tx_res_if) {
670 kfree(wl->fw_status);
671 return -ENOMEM;
672 }
673
674 INIT_WORK(&wl->irq_work, wl1271_irq_work);
675 INIT_WORK(&wl->tx_work, wl1271_tx_work);
676 return 0;
677}
678
679static int wl1271_chip_wakeup(struct wl1271 *wl)
680{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300681 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 int ret = 0;
683
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200684 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200685 ret = wl1271_power_on(wl);
686 if (ret < 0)
687 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200689 wl1271_io_reset(wl);
690 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691
692 /* We don't need a real memory partition here, because we only want
693 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300694 memset(&partition, 0, sizeof(partition));
695 partition.reg.start = REGISTERS_BASE;
696 partition.reg.size = REGISTERS_DOWN_SIZE;
697 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698
699 /* ELP module wake up */
700 wl1271_fw_wakeup(wl);
701
702 /* whal_FwCtrl_BootSm() */
703
704 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200705 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706
707 /* 1. check if chip id is valid */
708
709 switch (wl->chip.id) {
710 case CHIP_ID_1271_PG10:
711 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
712 wl->chip.id);
713
714 ret = wl1271_setup(wl);
715 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200716 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717 break;
718 case CHIP_ID_1271_PG20:
719 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
720 wl->chip.id);
721
722 ret = wl1271_setup(wl);
723 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200724 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725 break;
726 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200727 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300728 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200729 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730 }
731
732 if (wl->fw == NULL) {
733 ret = wl1271_fetch_firmware(wl);
734 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200735 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 }
737
738 /* No NVS from netlink, try to get it from the filesystem */
739 if (wl->nvs == NULL) {
740 ret = wl1271_fetch_nvs(wl);
741 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 }
744
745out:
746 return ret;
747}
748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749int wl1271_plt_start(struct wl1271 *wl)
750{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200751 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752 int ret;
753
754 mutex_lock(&wl->mutex);
755
756 wl1271_notice("power up");
757
758 if (wl->state != WL1271_STATE_OFF) {
759 wl1271_error("cannot go into PLT state because not "
760 "in off state: %d", wl->state);
761 ret = -EBUSY;
762 goto out;
763 }
764
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200765 while (retries) {
766 retries--;
767 ret = wl1271_chip_wakeup(wl);
768 if (ret < 0)
769 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200771 ret = wl1271_boot(wl);
772 if (ret < 0)
773 goto power_off;
774
775 ret = wl1271_plt_init(wl);
776 if (ret < 0)
777 goto irq_disable;
778
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200779 wl->state = WL1271_STATE_PLT;
780 wl1271_notice("firmware booted in PLT mode (%s)",
781 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782 goto out;
783
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200784irq_disable:
785 wl1271_disable_interrupts(wl);
786 mutex_unlock(&wl->mutex);
787 /* Unlocking the mutex in the middle of handling is
788 inherently unsafe. In this case we deem it safe to do,
789 because we need to let any possibly pending IRQ out of
790 the system (and while we are WL1271_STATE_OFF the IRQ
791 work function will not do anything.) Also, any other
792 possible concurrent operations will fail due to the
793 current state, hence the wl1271 struct should be safe. */
794 cancel_work_sync(&wl->irq_work);
795 mutex_lock(&wl->mutex);
796power_off:
797 wl1271_power_off(wl);
798 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300799
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200800 wl1271_error("firmware boot in PLT mode failed despite %d retries",
801 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802out:
803 mutex_unlock(&wl->mutex);
804
805 return ret;
806}
807
808int wl1271_plt_stop(struct wl1271 *wl)
809{
810 int ret = 0;
811
812 mutex_lock(&wl->mutex);
813
814 wl1271_notice("power down");
815
816 if (wl->state != WL1271_STATE_PLT) {
817 wl1271_error("cannot power down because not in PLT "
818 "state: %d", wl->state);
819 ret = -EBUSY;
820 goto out;
821 }
822
823 wl1271_disable_interrupts(wl);
824 wl1271_power_off(wl);
825
826 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300827 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
829out:
830 mutex_unlock(&wl->mutex);
831
832 return ret;
833}
834
835
836static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
837{
838 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200839 struct ieee80211_conf *conf = &hw->conf;
840 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
841 struct ieee80211_sta *sta = txinfo->control.sta;
842 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200844 /* peek into the rates configured in the STA entry */
845 spin_lock_irqsave(&wl->wl_lock, flags);
846 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
847 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
848 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
849 }
850 spin_unlock_irqrestore(&wl->wl_lock, flags);
851
852 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 skb_queue_tail(&wl->tx_queue, skb);
854
855 /*
856 * The chip specific setup must run before the first TX packet -
857 * before that, the tx_work will not be initialized!
858 */
859
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300860 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861
862 /*
863 * The workqueue is slow to process the tx_queue and we need stop
864 * the queue here, otherwise the queue will get too long.
865 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200866 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
867 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300868
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200869 spin_lock_irqsave(&wl->wl_lock, flags);
870 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200871 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200872 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873 }
874
875 return NETDEV_TX_OK;
876}
877
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300878static struct notifier_block wl1271_dev_notifier = {
879 .notifier_call = wl1271_dev_notify,
880};
881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882static int wl1271_op_start(struct ieee80211_hw *hw)
883{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200884 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
885
886 /*
887 * We have to delay the booting of the hardware because
888 * we need to know the local MAC address before downloading and
889 * initializing the firmware. The MAC address cannot be changed
890 * after boot, and without the proper MAC address, the firmware
891 * will not function properly.
892 *
893 * The MAC address is first known when the corresponding interface
894 * is added. That is where we will initialize the hardware.
895 */
896
897 return 0;
898}
899
900static void wl1271_op_stop(struct ieee80211_hw *hw)
901{
902 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
903}
904
905static int wl1271_op_add_interface(struct ieee80211_hw *hw,
906 struct ieee80211_vif *vif)
907{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400909 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200910 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911 int ret = 0;
912
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200913 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
914 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915
916 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200917 if (wl->vif) {
918 ret = -EBUSY;
919 goto out;
920 }
921
922 wl->vif = vif;
923
924 switch (vif->type) {
925 case NL80211_IFTYPE_STATION:
926 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200927 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200928 break;
929 case NL80211_IFTYPE_ADHOC:
930 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200931 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200932 break;
933 default:
934 ret = -EOPNOTSUPP;
935 goto out;
936 }
937
938 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939
940 if (wl->state != WL1271_STATE_OFF) {
941 wl1271_error("cannot start because not in off state: %d",
942 wl->state);
943 ret = -EBUSY;
944 goto out;
945 }
946
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200947 while (retries) {
948 retries--;
949 ret = wl1271_chip_wakeup(wl);
950 if (ret < 0)
951 goto power_off;
952
953 ret = wl1271_boot(wl);
954 if (ret < 0)
955 goto power_off;
956
957 ret = wl1271_hw_init(wl);
958 if (ret < 0)
959 goto irq_disable;
960
961 wl->state = WL1271_STATE_ON;
962 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400963
964 /* update hw/fw version info in wiphy struct */
965 wiphy->hw_version = wl->chip.id;
966 strncpy(wiphy->fw_version, wl->chip.fw_ver,
967 sizeof(wiphy->fw_version));
968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 goto out;
970
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200971irq_disable:
972 wl1271_disable_interrupts(wl);
973 mutex_unlock(&wl->mutex);
974 /* Unlocking the mutex in the middle of handling is
975 inherently unsafe. In this case we deem it safe to do,
976 because we need to let any possibly pending IRQ out of
977 the system (and while we are WL1271_STATE_OFF the IRQ
978 work function will not do anything.) Also, any other
979 possible concurrent operations will fail due to the
980 current state, hence the wl1271 struct should be safe. */
981 cancel_work_sync(&wl->irq_work);
982 mutex_lock(&wl->mutex);
983power_off:
984 wl1271_power_off(wl);
985 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200987 wl1271_error("firmware boot failed despite %d retries",
988 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300989out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 mutex_unlock(&wl->mutex);
991
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300992 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300993 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 return ret;
996}
997
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200998static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
999 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000{
1001 struct wl1271 *wl = hw->priv;
1002 int i;
1003
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001004 mutex_lock(&wl->mutex);
1005 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001007 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001009 list_del(&wl->list);
1010
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 WARN_ON(wl->state != WL1271_STATE_ON);
1012
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001013 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001014 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001015 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001016
Luciano Coelho08688d62010-07-08 17:50:07 +03001017 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 ieee80211_scan_completed(wl->hw, true);
Luciano Coelho08688d62010-07-08 17:50:07 +03001019 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1020 kfree(wl->scan.scanned_ch);
1021 wl->scan.scanned_ch = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 }
1023
1024 wl->state = WL1271_STATE_OFF;
1025
1026 wl1271_disable_interrupts(wl);
1027
1028 mutex_unlock(&wl->mutex);
1029
1030 cancel_work_sync(&wl->irq_work);
1031 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001032 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
1034 mutex_lock(&wl->mutex);
1035
1036 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001037 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 wl1271_power_off(wl);
1039
1040 memset(wl->bssid, 0, ETH_ALEN);
1041 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1042 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001044 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001045 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
1047 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001048 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1050 wl->tx_blocks_available = 0;
1051 wl->tx_results_count = 0;
1052 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001053 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001054 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 wl->time_offset = 0;
1056 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001057 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1058 wl->sta_rate_set = 0;
1059 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001060 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001061 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 for (i = 0; i < NUM_TX_QUEUES; i++)
1064 wl->tx_blocks_freed[i] = 0;
1065
1066 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001067
1068 kfree(wl->fw_status);
1069 wl->fw_status = NULL;
1070 kfree(wl->tx_res_if);
1071 wl->tx_res_if = NULL;
1072 kfree(wl->target_mem_map);
1073 wl->target_mem_map = NULL;
1074
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 mutex_unlock(&wl->mutex);
1076}
1077
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001078static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1079{
1080 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1081 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1082
1083 /* combine requested filters with current filter config */
1084 filters = wl->filters | filters;
1085
1086 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1087
1088 if (filters & FIF_PROMISC_IN_BSS) {
1089 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1090 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1091 wl->rx_config |= CFG_BSSID_FILTER_EN;
1092 }
1093 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1094 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1095 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1096 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1097 }
1098 if (filters & FIF_OTHER_BSS) {
1099 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1100 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1101 }
1102 if (filters & FIF_CONTROL) {
1103 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1104 wl->rx_filter |= CFG_RX_CTL_EN;
1105 }
1106 if (filters & FIF_FCSFAIL) {
1107 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1108 wl->rx_filter |= CFG_RX_FCS_ERROR;
1109 }
1110}
1111
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001112static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001113{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001114 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001115 /* we need to use a dummy BSSID for now */
1116 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1117 0xad, 0xbe, 0xef };
1118
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001119 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1120
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001121 /* pass through frames from all BSS */
1122 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1123
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001124 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001125 if (ret < 0)
1126 goto out;
1127
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001128 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001129
1130out:
1131 return ret;
1132}
1133
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001134static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001135{
1136 int ret;
1137
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001138 /*
1139 * One of the side effects of the JOIN command is that is clears
1140 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1141 * to a WPA/WPA2 access point will therefore kill the data-path.
1142 * Currently there is no supported scenario for JOIN during
1143 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1144 * must be handled somehow.
1145 *
1146 */
1147 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1148 wl1271_info("JOIN while associated.");
1149
1150 if (set_assoc)
1151 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1152
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001153 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1154 if (ret < 0)
1155 goto out;
1156
1157 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1158
1159 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1160 goto out;
1161
1162 /*
1163 * The join command disable the keep-alive mode, shut down its process,
1164 * and also clear the template config, so we need to reset it all after
1165 * the join. The acx_aid starts the keep-alive process, and the order
1166 * of the commands below is relevant.
1167 */
1168 ret = wl1271_acx_keep_alive_mode(wl, true);
1169 if (ret < 0)
1170 goto out;
1171
1172 ret = wl1271_acx_aid(wl, wl->aid);
1173 if (ret < 0)
1174 goto out;
1175
1176 ret = wl1271_cmd_build_klv_null_data(wl);
1177 if (ret < 0)
1178 goto out;
1179
1180 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1181 ACX_KEEP_ALIVE_TPL_VALID);
1182 if (ret < 0)
1183 goto out;
1184
1185out:
1186 return ret;
1187}
1188
1189static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001190{
1191 int ret;
1192
1193 /* to stop listening to a channel, we disconnect */
1194 ret = wl1271_cmd_disconnect(wl);
1195 if (ret < 0)
1196 goto out;
1197
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001198 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001199 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001200
1201 /* stop filterting packets based on bssid */
1202 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203
1204out:
1205 return ret;
1206}
1207
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001208static void wl1271_set_band_rate(struct wl1271 *wl)
1209{
1210 if (wl->band == IEEE80211_BAND_2GHZ)
1211 wl->basic_rate_set = wl->conf.tx.basic_rate;
1212 else
1213 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1214}
1215
1216static u32 wl1271_min_rate_get(struct wl1271 *wl)
1217{
1218 int i;
1219 u32 rate = 0;
1220
1221 if (!wl->basic_rate_set) {
1222 WARN_ON(1);
1223 wl->basic_rate_set = wl->conf.tx.basic_rate;
1224 }
1225
1226 for (i = 0; !rate; i++) {
1227 if ((wl->basic_rate_set >> i) & 0x1)
1228 rate = 1 << i;
1229 }
1230
1231 return rate;
1232}
1233
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001234static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1235{
1236 int ret;
1237
1238 if (idle) {
1239 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1240 ret = wl1271_unjoin(wl);
1241 if (ret < 0)
1242 goto out;
1243 }
1244 wl->rate_set = wl1271_min_rate_get(wl);
1245 wl->sta_rate_set = 0;
1246 ret = wl1271_acx_rate_policies(wl);
1247 if (ret < 0)
1248 goto out;
1249 ret = wl1271_acx_keep_alive_config(
1250 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1251 ACX_KEEP_ALIVE_TPL_INVALID);
1252 if (ret < 0)
1253 goto out;
1254 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1255 } else {
1256 /* increment the session counter */
1257 wl->session_counter++;
1258 if (wl->session_counter >= SESSION_COUNTER_MAX)
1259 wl->session_counter = 0;
1260 ret = wl1271_dummy_join(wl);
1261 if (ret < 0)
1262 goto out;
1263 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1264 }
1265
1266out:
1267 return ret;
1268}
1269
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1271{
1272 struct wl1271 *wl = hw->priv;
1273 struct ieee80211_conf *conf = &hw->conf;
1274 int channel, ret = 0;
1275
1276 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1277
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001278 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 channel,
1280 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001281 conf->power_level,
1282 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001284 /*
1285 * mac80211 will go to idle nearly immediately after transmitting some
1286 * frames, such as the deauth. To make sure those frames reach the air,
1287 * wait here until the TX queue is fully flushed.
1288 */
1289 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1290 (conf->flags & IEEE80211_CONF_IDLE))
1291 wl1271_tx_flush(wl);
1292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 mutex_lock(&wl->mutex);
1294
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001295 if (unlikely(wl->state == WL1271_STATE_OFF))
1296 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 ret = wl1271_ps_elp_wakeup(wl, false);
1299 if (ret < 0)
1300 goto out;
1301
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001302 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001303 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1304 ((wl->band != conf->channel->band) ||
1305 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001306 wl->band = conf->channel->band;
1307 wl->channel = channel;
1308
1309 /*
1310 * FIXME: the mac80211 should really provide a fixed rate
1311 * to use here. for now, just use the smallest possible rate
1312 * for the band as a fixed rate for association frames and
1313 * other control messages.
1314 */
1315 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1316 wl1271_set_band_rate(wl);
1317
1318 wl->basic_rate = wl1271_min_rate_get(wl);
1319 ret = wl1271_acx_rate_policies(wl);
1320 if (ret < 0)
1321 wl1271_warning("rate policy for update channel "
1322 "failed %d", ret);
1323
1324 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001325 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001326 if (ret < 0)
1327 wl1271_warning("cmd join to update channel "
1328 "failed %d", ret);
1329 }
1330 }
1331
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001332 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001333 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1334 if (ret < 0)
1335 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336 }
1337
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001338 /*
1339 * if mac80211 changes the PSM mode, make sure the mode is not
1340 * incorrectly changed after the pspoll failure active window.
1341 */
1342 if (changed & IEEE80211_CONF_CHANGE_PS)
1343 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1344
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001345 if (conf->flags & IEEE80211_CONF_PS &&
1346 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1347 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348
1349 /*
1350 * We enter PSM only if we're already associated.
1351 * If we're not, we'll enter it when joining an SSID,
1352 * through the bss_info_changed() hook.
1353 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001354 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001355 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001356 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1357 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001358 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001360 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001361 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001363 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001365 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001366 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1367 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 }
1369
1370 if (conf->power_level != wl->power_level) {
1371 ret = wl1271_acx_tx_power(wl, conf->power_level);
1372 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001373 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374
1375 wl->power_level = conf->power_level;
1376 }
1377
1378out_sleep:
1379 wl1271_ps_elp_sleep(wl);
1380
1381out:
1382 mutex_unlock(&wl->mutex);
1383
1384 return ret;
1385}
1386
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001387struct wl1271_filter_params {
1388 bool enabled;
1389 int mc_list_length;
1390 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1391};
1392
Jiri Pirko22bedad2010-04-01 21:22:57 +00001393static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1394 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001395{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001396 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001397 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001398 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001399
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001400 if (unlikely(wl->state == WL1271_STATE_OFF))
1401 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001402
Juuso Oikarinen74441132009-10-13 12:47:53 +03001403 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001404 if (!fp) {
1405 wl1271_error("Out of memory setting filters.");
1406 return 0;
1407 }
1408
1409 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001410 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001411 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1412 fp->enabled = false;
1413 } else {
1414 fp->enabled = true;
1415 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001416 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001417 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001418 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001419 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001420 }
1421
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001422 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001423}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001425#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1426 FIF_ALLMULTI | \
1427 FIF_FCSFAIL | \
1428 FIF_BCN_PRBRESP_PROMISC | \
1429 FIF_CONTROL | \
1430 FIF_OTHER_BSS)
1431
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1433 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001434 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001436 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001438 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439
1440 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1441
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001442 mutex_lock(&wl->mutex);
1443
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001444 *total &= WL1271_SUPPORTED_FILTERS;
1445 changed &= WL1271_SUPPORTED_FILTERS;
1446
1447 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001448 goto out;
1449
1450 ret = wl1271_ps_elp_wakeup(wl, false);
1451 if (ret < 0)
1452 goto out;
1453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001455 if (*total & FIF_ALLMULTI)
1456 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1457 else if (fp)
1458 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1459 fp->mc_list,
1460 fp->mc_list_length);
1461 if (ret < 0)
1462 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001464 /* determine, whether supported filter values have changed */
1465 if (changed == 0)
1466 goto out_sleep;
1467
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001468 /* configure filters */
1469 wl->filters = *total;
1470 wl1271_configure_filters(wl, 0);
1471
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001472 /* apply configured filters */
1473 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1474 if (ret < 0)
1475 goto out_sleep;
1476
1477out_sleep:
1478 wl1271_ps_elp_sleep(wl);
1479
1480out:
1481 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001482 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483}
1484
1485static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1486 struct ieee80211_vif *vif,
1487 struct ieee80211_sta *sta,
1488 struct ieee80211_key_conf *key_conf)
1489{
1490 struct wl1271 *wl = hw->priv;
1491 const u8 *addr;
1492 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001493 u32 tx_seq_32 = 0;
1494 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 u8 key_type;
1496
1497 static const u8 bcast_addr[ETH_ALEN] =
1498 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1499
1500 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1501
1502 addr = sta ? sta->addr : bcast_addr;
1503
1504 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1505 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1506 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001507 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 key_conf->keylen, key_conf->flags);
1509 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1510
1511 if (is_zero_ether_addr(addr)) {
1512 /* We dont support TX only encryption */
1513 ret = -EOPNOTSUPP;
1514 goto out;
1515 }
1516
1517 mutex_lock(&wl->mutex);
1518
1519 ret = wl1271_ps_elp_wakeup(wl, false);
1520 if (ret < 0)
1521 goto out_unlock;
1522
Johannes Berg97359d12010-08-10 09:46:38 +02001523 switch (key_conf->cipher) {
1524 case WLAN_CIPHER_SUITE_WEP40:
1525 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 key_type = KEY_WEP;
1527
1528 key_conf->hw_key_idx = key_conf->keyidx;
1529 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001530 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 key_type = KEY_TKIP;
1532
1533 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001534 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1535 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001537 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538 key_type = KEY_AES;
1539
1540 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001541 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1542 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 break;
1544 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001545 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546
1547 ret = -EOPNOTSUPP;
1548 goto out_sleep;
1549 }
1550
1551 switch (cmd) {
1552 case SET_KEY:
1553 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1554 key_conf->keyidx, key_type,
1555 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001556 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 if (ret < 0) {
1558 wl1271_error("Could not add or replace key");
1559 goto out_sleep;
1560 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001561
1562 /* the default WEP key needs to be configured at least once */
1563 if (key_type == KEY_WEP) {
1564 ret = wl1271_cmd_set_default_wep_key(wl,
1565 wl->default_key);
1566 if (ret < 0)
1567 goto out_sleep;
1568 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 break;
1570
1571 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001572 /* The wl1271 does not allow to remove unicast keys - they
1573 will be cleared automatically on next CMD_JOIN. Ignore the
1574 request silently, as we dont want the mac80211 to emit
1575 an error message. */
1576 if (!is_broadcast_ether_addr(addr))
1577 break;
1578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1580 key_conf->keyidx, key_type,
1581 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001582 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 if (ret < 0) {
1584 wl1271_error("Could not remove key");
1585 goto out_sleep;
1586 }
1587 break;
1588
1589 default:
1590 wl1271_error("Unsupported key cmd 0x%x", cmd);
1591 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 break;
1593 }
1594
1595out_sleep:
1596 wl1271_ps_elp_sleep(wl);
1597
1598out_unlock:
1599 mutex_unlock(&wl->mutex);
1600
1601out:
1602 return ret;
1603}
1604
1605static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001606 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607 struct cfg80211_scan_request *req)
1608{
1609 struct wl1271 *wl = hw->priv;
1610 int ret;
1611 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001612 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001613
1614 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1615
1616 if (req->n_ssids) {
1617 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001618 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 }
1620
1621 mutex_lock(&wl->mutex);
1622
1623 ret = wl1271_ps_elp_wakeup(wl, false);
1624 if (ret < 0)
1625 goto out;
1626
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001627 if (wl1271_11a_enabled())
Luciano Coelho08688d62010-07-08 17:50:07 +03001628 ret = wl1271_scan(hw->priv, ssid, len, req);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001629 else
Luciano Coelho08688d62010-07-08 17:50:07 +03001630 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631
1632 wl1271_ps_elp_sleep(wl);
1633
1634out:
1635 mutex_unlock(&wl->mutex);
1636
1637 return ret;
1638}
1639
1640static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1641{
1642 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001643 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001644
1645 mutex_lock(&wl->mutex);
1646
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001647 if (unlikely(wl->state == WL1271_STATE_OFF))
1648 goto out;
1649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 ret = wl1271_ps_elp_wakeup(wl, false);
1651 if (ret < 0)
1652 goto out;
1653
1654 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1655 if (ret < 0)
1656 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1657
1658 wl1271_ps_elp_sleep(wl);
1659
1660out:
1661 mutex_unlock(&wl->mutex);
1662
1663 return ret;
1664}
1665
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001666static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1667{
1668 u8 *ptr = beacon->data +
1669 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1670
1671 /* find the location of the ssid in the beacon */
1672 while (ptr < beacon->data + beacon->len) {
1673 if (ptr[0] == WLAN_EID_SSID) {
1674 wl->ssid_len = ptr[1];
1675 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1676 return;
1677 }
1678 ptr += ptr[1];
1679 }
1680 wl1271_error("ad-hoc beacon template has no SSID!\n");
1681}
1682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1684 struct ieee80211_vif *vif,
1685 struct ieee80211_bss_conf *bss_conf,
1686 u32 changed)
1687{
1688 enum wl1271_cmd_ps_mode mode;
1689 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001690 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001691 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001692 int ret;
1693
1694 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1695
1696 mutex_lock(&wl->mutex);
1697
1698 ret = wl1271_ps_elp_wakeup(wl, false);
1699 if (ret < 0)
1700 goto out;
1701
Eliad Peller9ee82d52010-09-19 18:55:09 +02001702 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001703 (wl->bss_type == BSS_TYPE_IBSS)) {
1704 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1705 bss_conf->beacon_int);
1706
1707 wl->beacon_int = bss_conf->beacon_int;
1708 do_join = true;
1709 }
1710
Eliad Peller9ee82d52010-09-19 18:55:09 +02001711 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001712 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001713 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1714
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001715 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1716
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001717 if (beacon) {
1718 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001719
1720 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001721 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1722 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001723 beacon->len, 0,
1724 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001725
1726 if (ret < 0) {
1727 dev_kfree_skb(beacon);
1728 goto out_sleep;
1729 }
1730
1731 hdr = (struct ieee80211_hdr *) beacon->data;
1732 hdr->frame_control = cpu_to_le16(
1733 IEEE80211_FTYPE_MGMT |
1734 IEEE80211_STYPE_PROBE_RESP);
1735
1736 ret = wl1271_cmd_template_set(wl,
1737 CMD_TEMPL_PROBE_RESPONSE,
1738 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001739 beacon->len, 0,
1740 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001741 dev_kfree_skb(beacon);
1742 if (ret < 0)
1743 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001744
1745 /* Need to update the SSID (for filtering etc) */
1746 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001747 }
1748 }
1749
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001750 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1751 (wl->bss_type == BSS_TYPE_IBSS)) {
1752 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1753 bss_conf->enable_beacon ? "enabled" : "disabled");
1754
1755 if (bss_conf->enable_beacon)
1756 wl->set_bss_type = BSS_TYPE_IBSS;
1757 else
1758 wl->set_bss_type = BSS_TYPE_STA_BSS;
1759 do_join = true;
1760 }
1761
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001762 if (changed & BSS_CHANGED_CQM) {
1763 bool enable = false;
1764 if (bss_conf->cqm_rssi_thold)
1765 enable = true;
1766 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1767 bss_conf->cqm_rssi_thold,
1768 bss_conf->cqm_rssi_hyst);
1769 if (ret < 0)
1770 goto out;
1771 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1772 }
1773
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001774 if ((changed & BSS_CHANGED_BSSID) &&
1775 /*
1776 * Now we know the correct bssid, so we send a new join command
1777 * and enable the BSSID filter
1778 */
1779 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001780 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001781
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001782 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001783 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001784 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001785
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001786 ret = wl1271_build_qos_null_data(wl);
1787 if (ret < 0)
1788 goto out_sleep;
1789
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001790 /* filter out all packets not from this BSSID */
1791 wl1271_configure_filters(wl, 0);
1792
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001793 /* Need to update the BSSID (for filtering etc) */
1794 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001795 }
1796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797 if (changed & BSS_CHANGED_ASSOC) {
1798 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001799 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001801 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001803 wl->ps_poll_failures = 0;
1804
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001805 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001806 * use basic rates from AP, and determine lowest rate
1807 * to use with control frames.
1808 */
1809 rates = bss_conf->basic_rates;
1810 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1811 rates);
1812 wl->basic_rate = wl1271_min_rate_get(wl);
1813 ret = wl1271_acx_rate_policies(wl);
1814 if (ret < 0)
1815 goto out_sleep;
1816
1817 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001818 * with wl1271, we don't need to update the
1819 * beacon_int and dtim_period, because the firmware
1820 * updates it by itself when the first beacon is
1821 * received after a join.
1822 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1824 if (ret < 0)
1825 goto out_sleep;
1826
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001827 /*
1828 * The SSID is intentionally set to NULL here - the
1829 * firmware will set the probe request with a
1830 * broadcast SSID regardless of what we set in the
1831 * template.
1832 */
1833 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1834 NULL, 0, wl->band);
1835
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001836 /* enable the connection monitoring feature */
1837 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001838 if (ret < 0)
1839 goto out_sleep;
1840
1841 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001842 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1843 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001845 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 if (ret < 0)
1847 goto out_sleep;
1848 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001849 } else {
1850 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001851 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001852 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001853 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001854
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001855 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001856 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001857
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001858 /* revert back to minimum rates for the current band */
1859 wl1271_set_band_rate(wl);
1860 wl->basic_rate = wl1271_min_rate_get(wl);
1861 ret = wl1271_acx_rate_policies(wl);
1862 if (ret < 0)
1863 goto out_sleep;
1864
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001865 /* disable connection monitor features */
1866 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001867
1868 /* Disable the keep-alive feature */
1869 ret = wl1271_acx_keep_alive_mode(wl, false);
1870
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001871 if (ret < 0)
1872 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001874
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001876
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 if (changed & BSS_CHANGED_ERP_SLOT) {
1878 if (bss_conf->use_short_slot)
1879 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1880 else
1881 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1882 if (ret < 0) {
1883 wl1271_warning("Set slot time failed %d", ret);
1884 goto out_sleep;
1885 }
1886 }
1887
1888 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1889 if (bss_conf->use_short_preamble)
1890 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1891 else
1892 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1893 }
1894
1895 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1896 if (bss_conf->use_cts_prot)
1897 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1898 else
1899 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1900 if (ret < 0) {
1901 wl1271_warning("Set ctsprotect failed %d", ret);
1902 goto out_sleep;
1903 }
1904 }
1905
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001906 if (changed & BSS_CHANGED_ARP_FILTER) {
1907 __be32 addr = bss_conf->arp_addr_list[0];
1908 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1909
1910 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1911 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1912 else
1913 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1914
1915 if (ret < 0)
1916 goto out_sleep;
1917 }
1918
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001919 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001920 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001921 if (ret < 0) {
1922 wl1271_warning("cmd join failed %d", ret);
1923 goto out_sleep;
1924 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001925 }
1926
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927out_sleep:
1928 wl1271_ps_elp_sleep(wl);
1929
1930out:
1931 mutex_unlock(&wl->mutex);
1932}
1933
Kalle Valoc6999d82010-02-18 13:25:41 +02001934static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1935 const struct ieee80211_tx_queue_params *params)
1936{
1937 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001938 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001939 int ret;
1940
1941 mutex_lock(&wl->mutex);
1942
1943 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1944
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001945 ret = wl1271_ps_elp_wakeup(wl, false);
1946 if (ret < 0)
1947 goto out;
1948
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001949 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001950 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1951 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001952 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001953 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001954 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001955
Kalle Valo4695dc92010-03-18 12:26:38 +02001956 if (params->uapsd)
1957 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1958 else
1959 ps_scheme = CONF_PS_SCHEME_LEGACY;
1960
Kalle Valoc6999d82010-02-18 13:25:41 +02001961 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1962 CONF_CHANNEL_TYPE_EDCF,
1963 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001964 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001965 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001966 goto out_sleep;
1967
1968out_sleep:
1969 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001970
1971out:
1972 mutex_unlock(&wl->mutex);
1973
1974 return ret;
1975}
1976
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001977static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1978{
1979
1980 struct wl1271 *wl = hw->priv;
1981 u64 mactime = ULLONG_MAX;
1982 int ret;
1983
1984 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1985
1986 mutex_lock(&wl->mutex);
1987
1988 ret = wl1271_ps_elp_wakeup(wl, false);
1989 if (ret < 0)
1990 goto out;
1991
1992 ret = wl1271_acx_tsf_info(wl, &mactime);
1993 if (ret < 0)
1994 goto out_sleep;
1995
1996out_sleep:
1997 wl1271_ps_elp_sleep(wl);
1998
1999out:
2000 mutex_unlock(&wl->mutex);
2001 return mactime;
2002}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003
John W. Linvilleece550d2010-07-28 16:41:06 -04002004static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2005 struct survey_info *survey)
2006{
2007 struct wl1271 *wl = hw->priv;
2008 struct ieee80211_conf *conf = &hw->conf;
2009
2010 if (idx != 0)
2011 return -ENOENT;
2012
2013 survey->channel = conf->channel;
2014 survey->filled = SURVEY_INFO_NOISE_DBM;
2015 survey->noise = wl->noise;
2016
2017 return 0;
2018}
2019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020/* can't be const, mac80211 writes to this */
2021static struct ieee80211_rate wl1271_rates[] = {
2022 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002023 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2024 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002026 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2027 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2029 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002030 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2033 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002034 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2035 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2037 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002038 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2039 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002041 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2042 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002043 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002044 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2045 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002047 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2048 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002050 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2051 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002053 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2054 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002056 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2057 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002059 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2060 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061};
2062
2063/* can't be const, mac80211 writes to this */
2064static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002065 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
2066 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2067 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2068 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2069 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
2070 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2071 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2072 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2073 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
2074 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
2075 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2076 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2077 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078};
2079
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002080/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002081static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002082 /* MCS rates are used only with 11n */
2083 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2084 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2085 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2086 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2087 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2088 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2089 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2090 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2091
2092 11, /* CONF_HW_RXTX_RATE_54 */
2093 10, /* CONF_HW_RXTX_RATE_48 */
2094 9, /* CONF_HW_RXTX_RATE_36 */
2095 8, /* CONF_HW_RXTX_RATE_24 */
2096
2097 /* TI-specific rate */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2099
2100 7, /* CONF_HW_RXTX_RATE_18 */
2101 6, /* CONF_HW_RXTX_RATE_12 */
2102 3, /* CONF_HW_RXTX_RATE_11 */
2103 5, /* CONF_HW_RXTX_RATE_9 */
2104 4, /* CONF_HW_RXTX_RATE_6 */
2105 2, /* CONF_HW_RXTX_RATE_5_5 */
2106 1, /* CONF_HW_RXTX_RATE_2 */
2107 0 /* CONF_HW_RXTX_RATE_1 */
2108};
2109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110/* can't be const, mac80211 writes to this */
2111static struct ieee80211_supported_band wl1271_band_2ghz = {
2112 .channels = wl1271_channels,
2113 .n_channels = ARRAY_SIZE(wl1271_channels),
2114 .bitrates = wl1271_rates,
2115 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2116};
2117
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002118/* 5 GHz data rates for WL1273 */
2119static struct ieee80211_rate wl1271_rates_5ghz[] = {
2120 { .bitrate = 60,
2121 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2122 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2123 { .bitrate = 90,
2124 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2125 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2126 { .bitrate = 120,
2127 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2128 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2129 { .bitrate = 180,
2130 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2131 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2132 { .bitrate = 240,
2133 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2134 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2135 { .bitrate = 360,
2136 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2137 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2138 { .bitrate = 480,
2139 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2140 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2141 { .bitrate = 540,
2142 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2143 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2144};
2145
2146/* 5 GHz band channels for WL1273 */
2147static struct ieee80211_channel wl1271_channels_5ghz[] = {
2148 { .hw_value = 183, .center_freq = 4915},
2149 { .hw_value = 184, .center_freq = 4920},
2150 { .hw_value = 185, .center_freq = 4925},
2151 { .hw_value = 187, .center_freq = 4935},
2152 { .hw_value = 188, .center_freq = 4940},
2153 { .hw_value = 189, .center_freq = 4945},
2154 { .hw_value = 192, .center_freq = 4960},
2155 { .hw_value = 196, .center_freq = 4980},
2156 { .hw_value = 7, .center_freq = 5035},
2157 { .hw_value = 8, .center_freq = 5040},
2158 { .hw_value = 9, .center_freq = 5045},
2159 { .hw_value = 11, .center_freq = 5055},
2160 { .hw_value = 12, .center_freq = 5060},
2161 { .hw_value = 16, .center_freq = 5080},
2162 { .hw_value = 34, .center_freq = 5170},
2163 { .hw_value = 36, .center_freq = 5180},
2164 { .hw_value = 38, .center_freq = 5190},
2165 { .hw_value = 40, .center_freq = 5200},
2166 { .hw_value = 42, .center_freq = 5210},
2167 { .hw_value = 44, .center_freq = 5220},
2168 { .hw_value = 46, .center_freq = 5230},
2169 { .hw_value = 48, .center_freq = 5240},
2170 { .hw_value = 52, .center_freq = 5260},
2171 { .hw_value = 56, .center_freq = 5280},
2172 { .hw_value = 60, .center_freq = 5300},
2173 { .hw_value = 64, .center_freq = 5320},
2174 { .hw_value = 100, .center_freq = 5500},
2175 { .hw_value = 104, .center_freq = 5520},
2176 { .hw_value = 108, .center_freq = 5540},
2177 { .hw_value = 112, .center_freq = 5560},
2178 { .hw_value = 116, .center_freq = 5580},
2179 { .hw_value = 120, .center_freq = 5600},
2180 { .hw_value = 124, .center_freq = 5620},
2181 { .hw_value = 128, .center_freq = 5640},
2182 { .hw_value = 132, .center_freq = 5660},
2183 { .hw_value = 136, .center_freq = 5680},
2184 { .hw_value = 140, .center_freq = 5700},
2185 { .hw_value = 149, .center_freq = 5745},
2186 { .hw_value = 153, .center_freq = 5765},
2187 { .hw_value = 157, .center_freq = 5785},
2188 { .hw_value = 161, .center_freq = 5805},
2189 { .hw_value = 165, .center_freq = 5825},
2190};
2191
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002192/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002193static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002194 /* MCS rates are used only with 11n */
2195 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2196 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2197 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2198 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2199 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2200 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2201 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2202 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2203
2204 7, /* CONF_HW_RXTX_RATE_54 */
2205 6, /* CONF_HW_RXTX_RATE_48 */
2206 5, /* CONF_HW_RXTX_RATE_36 */
2207 4, /* CONF_HW_RXTX_RATE_24 */
2208
2209 /* TI-specific rate */
2210 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2211
2212 3, /* CONF_HW_RXTX_RATE_18 */
2213 2, /* CONF_HW_RXTX_RATE_12 */
2214 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2215 1, /* CONF_HW_RXTX_RATE_9 */
2216 0, /* CONF_HW_RXTX_RATE_6 */
2217 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2218 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2219 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2220};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002221
2222static struct ieee80211_supported_band wl1271_band_5ghz = {
2223 .channels = wl1271_channels_5ghz,
2224 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2225 .bitrates = wl1271_rates_5ghz,
2226 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2227};
2228
Tobias Klausera0ea9492010-05-20 10:38:11 +02002229static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002230 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2231 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2232};
2233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002234static const struct ieee80211_ops wl1271_ops = {
2235 .start = wl1271_op_start,
2236 .stop = wl1271_op_stop,
2237 .add_interface = wl1271_op_add_interface,
2238 .remove_interface = wl1271_op_remove_interface,
2239 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002240 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002241 .configure_filter = wl1271_op_configure_filter,
2242 .tx = wl1271_op_tx,
2243 .set_key = wl1271_op_set_key,
2244 .hw_scan = wl1271_op_hw_scan,
2245 .bss_info_changed = wl1271_op_bss_info_changed,
2246 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002247 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002248 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002249 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002250 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251};
2252
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002253
2254u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2255{
2256 u8 idx;
2257
2258 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2259
2260 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2261 wl1271_error("Illegal RX rate from HW: %d", rate);
2262 return 0;
2263 }
2264
2265 idx = wl1271_band_rate_to_idx[wl->band][rate];
2266 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2267 wl1271_error("Unsupported RX rate from HW: %d", rate);
2268 return 0;
2269 }
2270
2271 return idx;
2272}
2273
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002274static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2275 struct device_attribute *attr,
2276 char *buf)
2277{
2278 struct wl1271 *wl = dev_get_drvdata(dev);
2279 ssize_t len;
2280
2281 /* FIXME: what's the maximum length of buf? page size?*/
2282 len = 500;
2283
2284 mutex_lock(&wl->mutex);
2285 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2286 wl->sg_enabled);
2287 mutex_unlock(&wl->mutex);
2288
2289 return len;
2290
2291}
2292
2293static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2294 struct device_attribute *attr,
2295 const char *buf, size_t count)
2296{
2297 struct wl1271 *wl = dev_get_drvdata(dev);
2298 unsigned long res;
2299 int ret;
2300
2301 ret = strict_strtoul(buf, 10, &res);
2302
2303 if (ret < 0) {
2304 wl1271_warning("incorrect value written to bt_coex_mode");
2305 return count;
2306 }
2307
2308 mutex_lock(&wl->mutex);
2309
2310 res = !!res;
2311
2312 if (res == wl->sg_enabled)
2313 goto out;
2314
2315 wl->sg_enabled = res;
2316
2317 if (wl->state == WL1271_STATE_OFF)
2318 goto out;
2319
2320 ret = wl1271_ps_elp_wakeup(wl, false);
2321 if (ret < 0)
2322 goto out;
2323
2324 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2325 wl1271_ps_elp_sleep(wl);
2326
2327 out:
2328 mutex_unlock(&wl->mutex);
2329 return count;
2330}
2331
2332static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2333 wl1271_sysfs_show_bt_coex_state,
2334 wl1271_sysfs_store_bt_coex_state);
2335
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002336static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2337 struct device_attribute *attr,
2338 char *buf)
2339{
2340 struct wl1271 *wl = dev_get_drvdata(dev);
2341 ssize_t len;
2342
2343 /* FIXME: what's the maximum length of buf? page size?*/
2344 len = 500;
2345
2346 mutex_lock(&wl->mutex);
2347 if (wl->hw_pg_ver >= 0)
2348 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2349 else
2350 len = snprintf(buf, len, "n/a\n");
2351 mutex_unlock(&wl->mutex);
2352
2353 return len;
2354}
2355
2356static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2357 wl1271_sysfs_show_hw_pg_ver, NULL);
2358
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002359int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360{
2361 int ret;
2362
2363 if (wl->mac80211_registered)
2364 return 0;
2365
2366 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2367
2368 ret = ieee80211_register_hw(wl->hw);
2369 if (ret < 0) {
2370 wl1271_error("unable to register mac80211 hw: %d", ret);
2371 return ret;
2372 }
2373
2374 wl->mac80211_registered = true;
2375
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002376 register_netdevice_notifier(&wl1271_dev_notifier);
2377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378 wl1271_notice("loaded");
2379
2380 return 0;
2381}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002382EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002383
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002384void wl1271_unregister_hw(struct wl1271 *wl)
2385{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002386 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002387 ieee80211_unregister_hw(wl->hw);
2388 wl->mac80211_registered = false;
2389
2390}
2391EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2392
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002393int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002395 /* The tx descriptor buffer and the TKIP space. */
2396 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2397 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398
2399 /* unit us */
2400 /* FIXME: find a proper value */
2401 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002402 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403
2404 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002405 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002406 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002407 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002408 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002409 IEEE80211_HW_CONNECTION_MONITOR |
2410 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002411
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002412 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2413 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002414 wl->hw->wiphy->max_scan_ssids = 1;
2415 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2416
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002417 if (wl1271_11a_enabled())
2418 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2419
Kalle Valo12bd8942010-03-18 12:26:33 +02002420 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002421 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002422
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002423 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002424
2425 return 0;
2426}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002427EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002429#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002430
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002431struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002432{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002434 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002435 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002436 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437
2438 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2439 if (!hw) {
2440 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002441 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002442 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443 }
2444
Julia Lawall929ebd32010-05-15 23:16:39 +02002445 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002446 if (!plat_dev) {
2447 wl1271_error("could not allocate platform_device");
2448 ret = -ENOMEM;
2449 goto err_plat_alloc;
2450 }
2451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002452 wl = hw->priv;
2453 memset(wl, 0, sizeof(*wl));
2454
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002455 INIT_LIST_HEAD(&wl->list);
2456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002458 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002459
2460 skb_queue_head_init(&wl->tx_queue);
2461
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002462 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002463 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002465 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002467 wl->rx_counter = 0;
2468 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2469 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002470 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002472 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002474 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2475 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002476 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002477 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002478 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002479 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002480 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002482 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483 wl->tx_frames[i] = NULL;
2484
2485 spin_lock_init(&wl->wl_lock);
2486
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002487 wl->state = WL1271_STATE_OFF;
2488 mutex_init(&wl->mutex);
2489
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002490 /* Apply default driver configuration. */
2491 wl1271_conf_init(wl);
2492
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002493 wl1271_debugfs_init(wl);
2494
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002495 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002496 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002497 if (ret) {
2498 wl1271_error("couldn't register platform device");
2499 goto err_hw;
2500 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002501 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002502
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002503 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002504 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002505 if (ret < 0) {
2506 wl1271_error("failed to create sysfs file bt_coex_state");
2507 goto err_platform;
2508 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002509
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002510 /* Create sysfs file to get HW PG version */
2511 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2512 if (ret < 0) {
2513 wl1271_error("failed to create sysfs file hw_pg_ver");
2514 goto err_bt_coex_state;
2515 }
2516
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002517 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002518
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002519err_bt_coex_state:
2520 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2521
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002522err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002523 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002524
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002525err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002526 wl1271_debugfs_exit(wl);
2527 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002528
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002529err_plat_alloc:
2530 ieee80211_free_hw(hw);
2531
2532err_hw_alloc:
2533
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002534 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002535}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002536EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002537
2538int wl1271_free_hw(struct wl1271 *wl)
2539{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002540 platform_device_unregister(wl->plat_dev);
2541 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002542
2543 wl1271_debugfs_exit(wl);
2544
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002545 vfree(wl->fw);
2546 wl->fw = NULL;
2547 kfree(wl->nvs);
2548 wl->nvs = NULL;
2549
2550 kfree(wl->fw_status);
2551 kfree(wl->tx_res_if);
2552
2553 ieee80211_free_hw(wl->hw);
2554
2555 return 0;
2556}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002557EXPORT_SYMBOL_GPL(wl1271_free_hw);
2558
2559MODULE_LICENSE("GPL");
2560MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2561MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");