blob: c00523008be40c37158d712a29e87f40d771456b [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
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200217 .psm_entry_retries = 5,
218 .psm_entry_nullfunc_retries = 3,
219 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300220 .keep_alive_interval = 55000,
221 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200223 .itrim = {
224 .enable = false,
225 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200226 },
227 .pm_config = {
228 .host_clk_settling_time = 5000,
229 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 },
231 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300232 .trigger_pacing = 1,
233 .avg_weight_rssi_beacon = 20,
234 .avg_weight_rssi_data = 10,
235 .avg_weight_snr_beacon = 20,
236 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200237 },
238 .scan = {
239 .min_dwell_time_active = 7500,
240 .max_dwell_time_active = 30000,
241 .min_dwell_time_passive = 30000,
242 .max_dwell_time_passive = 60000,
243 .num_probe_reqs = 2,
244 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200245 .rf = {
246 .tx_per_channel_power_compensation_2 = {
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 },
249 .tx_per_channel_power_compensation_5 = {
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 },
254 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255};
256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200257static void __wl1271_op_remove_interface(struct wl1271 *wl);
258
259
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200260static void wl1271_device_release(struct device *dev)
261{
262
263}
264
265static struct platform_device wl1271_device = {
266 .name = "wl1271",
267 .id = -1,
268
269 /* device model insists to have a release function */
270 .dev = {
271 .release = wl1271_device_release,
272 },
273};
274
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300275static LIST_HEAD(wl_list);
276
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300277static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
278 void *arg)
279{
280 struct net_device *dev = arg;
281 struct wireless_dev *wdev;
282 struct wiphy *wiphy;
283 struct ieee80211_hw *hw;
284 struct wl1271 *wl;
285 struct wl1271 *wl_temp;
286 int ret = 0;
287
288 /* Check that this notification is for us. */
289 if (what != NETDEV_CHANGE)
290 return NOTIFY_DONE;
291
292 wdev = dev->ieee80211_ptr;
293 if (wdev == NULL)
294 return NOTIFY_DONE;
295
296 wiphy = wdev->wiphy;
297 if (wiphy == NULL)
298 return NOTIFY_DONE;
299
300 hw = wiphy_priv(wiphy);
301 if (hw == NULL)
302 return NOTIFY_DONE;
303
304 wl_temp = hw->priv;
305 list_for_each_entry(wl, &wl_list, list) {
306 if (wl == wl_temp)
307 break;
308 }
309 if (wl != wl_temp)
310 return NOTIFY_DONE;
311
312 mutex_lock(&wl->mutex);
313
314 if (wl->state == WL1271_STATE_OFF)
315 goto out;
316
317 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
318 goto out;
319
320 ret = wl1271_ps_elp_wakeup(wl, false);
321 if (ret < 0)
322 goto out;
323
324 if ((dev->operstate == IF_OPER_UP) &&
325 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
326 wl1271_cmd_set_sta_state(wl);
327 wl1271_info("Association completed.");
328 }
329
330 wl1271_ps_elp_sleep(wl);
331
332out:
333 mutex_unlock(&wl->mutex);
334
335 return NOTIFY_OK;
336}
337
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338static void wl1271_conf_init(struct wl1271 *wl)
339{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340
341 /*
342 * This function applies the default configuration to the driver. This
343 * function is invoked upon driver load (spi probe.)
344 *
345 * The configuration is stored in a run-time structure in order to
346 * facilitate for run-time adjustment of any of the parameters. Making
347 * changes to the configuration structure will apply the new values on
348 * the next interface up (wl1271_op_start.)
349 */
350
351 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300352 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300353}
354
355
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300356static int wl1271_plt_init(struct wl1271 *wl)
357{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200358 struct conf_tx_ac_category *conf_ac;
359 struct conf_tx_tid *conf_tid;
360 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200362 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200363 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200364 return ret;
365
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200366 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200367 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200368 return ret;
369
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200370 ret = wl1271_cmd_ext_radio_parms(wl);
371 if (ret < 0)
372 return ret;
373
Luciano Coelho12419cc2010-02-18 13:25:44 +0200374 ret = wl1271_init_templates_config(wl);
375 if (ret < 0)
376 return ret;
377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 ret = wl1271_acx_init_mem_config(wl);
379 if (ret < 0)
380 return ret;
381
Luciano Coelho12419cc2010-02-18 13:25:44 +0200382 /* PHY layer config */
383 ret = wl1271_init_phy_config(wl);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 ret = wl1271_acx_dco_itrim_params(wl);
388 if (ret < 0)
389 goto out_free_memmap;
390
391 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200392 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200393 if (ret < 0)
394 goto out_free_memmap;
395
396 /* Bluetooth WLAN coexistence */
397 ret = wl1271_init_pta(wl);
398 if (ret < 0)
399 goto out_free_memmap;
400
401 /* Energy detection */
402 ret = wl1271_init_energy_detection(wl);
403 if (ret < 0)
404 goto out_free_memmap;
405
406 /* Default fragmentation threshold */
407 ret = wl1271_acx_frag_threshold(wl);
408 if (ret < 0)
409 goto out_free_memmap;
410
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200411 /* Default TID/AC configuration */
412 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200413 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200414 conf_ac = &wl->conf.tx.ac_conf[i];
415 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
416 conf_ac->cw_max, conf_ac->aifsn,
417 conf_ac->tx_op_limit);
418 if (ret < 0)
419 goto out_free_memmap;
420
Luciano Coelho12419cc2010-02-18 13:25:44 +0200421 conf_tid = &wl->conf.tx.tid_conf[i];
422 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
423 conf_tid->channel_type,
424 conf_tid->tsid,
425 conf_tid->ps_scheme,
426 conf_tid->ack_policy,
427 conf_tid->apsd_conf[0],
428 conf_tid->apsd_conf[1]);
429 if (ret < 0)
430 goto out_free_memmap;
431 }
432
Luciano Coelho12419cc2010-02-18 13:25:44 +0200433 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200434 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200436 goto out_free_memmap;
437
438 /* Configure for CAM power saving (ie. always active) */
439 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
440 if (ret < 0)
441 goto out_free_memmap;
442
443 /* configure PM */
444 ret = wl1271_acx_pm_config(wl);
445 if (ret < 0)
446 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
448 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200449
450 out_free_memmap:
451 kfree(wl->target_mem_map);
452 wl->target_mem_map = NULL;
453
454 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455}
456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457static void wl1271_fw_status(struct wl1271 *wl,
458 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200460 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 u32 total = 0;
462 int i;
463
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200464 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
467 "drv_rx_counter = %d, tx_results_counter = %d)",
468 status->intr,
469 status->fw_rx_counter,
470 status->drv_rx_counter,
471 status->tx_results_counter);
472
473 /* update number of available TX blocks */
474 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300475 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
476 wl->tx_blocks_freed[i];
477
478 wl->tx_blocks_freed[i] =
479 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl->tx_blocks_available += cnt;
481 total += cnt;
482 }
483
Ido Yariva5225502010-10-12 14:49:10 +0200484 /* if more blocks are available now, tx work can be scheduled */
485 if (total)
486 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200489 getnstimeofday(&ts);
490 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
491 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492}
493
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200494#define WL1271_IRQ_MAX_LOOPS 10
495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496static void wl1271_irq_work(struct work_struct *work)
497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300499 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200500 int loopcount = WL1271_IRQ_MAX_LOOPS;
501 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 struct wl1271 *wl =
503 container_of(work, struct wl1271, irq_work);
504
505 mutex_lock(&wl->mutex);
506
507 wl1271_debug(DEBUG_IRQ, "IRQ work");
508
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 goto out;
511
512 ret = wl1271_ps_elp_wakeup(wl, true);
513 if (ret < 0)
514 goto out;
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516 spin_lock_irqsave(&wl->wl_lock, flags);
517 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
518 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520 loopcount--;
521
522 wl1271_fw_status(wl, wl->fw_status);
523 intr = le32_to_cpu(wl->fw_status->intr);
524 if (!intr) {
525 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200526 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200527 continue;
528 }
529
530 intr &= WL1271_INTR_MASK;
531
Eliad Pellerccc83b02010-10-27 14:09:57 +0200532 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
533 wl1271_error("watchdog interrupt received! "
534 "starting recovery.");
535 ieee80211_queue_work(wl->hw, &wl->recovery_work);
536
537 /* restarting the chip. ignore any other interrupt. */
538 goto out;
539 }
540
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200541 if (intr & WL1271_ACX_INTR_DATA) {
542 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
543
544 /* check for tx results */
545 if (wl->fw_status->tx_results_counter !=
546 (wl->tx_results_count & 0xff))
547 wl1271_tx_complete(wl);
548
Ido Yariva5225502010-10-12 14:49:10 +0200549 /* Check if any tx blocks were freed */
550 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
551 !skb_queue_empty(&wl->tx_queue)) {
552 /*
553 * In order to avoid starvation of the TX path,
554 * call the work function directly.
555 */
556 wl1271_tx_work_locked(wl);
557 }
558
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200559 wl1271_rx(wl, wl->fw_status);
560 }
561
562 if (intr & WL1271_ACX_INTR_EVENT_A) {
563 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
564 wl1271_event_handle(wl, 0);
565 }
566
567 if (intr & WL1271_ACX_INTR_EVENT_B) {
568 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
569 wl1271_event_handle(wl, 1);
570 }
571
572 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
573 wl1271_debug(DEBUG_IRQ,
574 "WL1271_ACX_INTR_INIT_COMPLETE");
575
576 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
577 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
578
579 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580 }
581
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200582 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
583 ieee80211_queue_work(wl->hw, &wl->irq_work);
584 else
585 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
586 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300588 wl1271_ps_elp_sleep(wl);
589
590out:
591 mutex_unlock(&wl->mutex);
592}
593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300594static int wl1271_fetch_firmware(struct wl1271 *wl)
595{
596 const struct firmware *fw;
597 int ret;
598
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200599 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600
601 if (ret < 0) {
602 wl1271_error("could not get firmware: %d", ret);
603 return ret;
604 }
605
606 if (fw->size % 4) {
607 wl1271_error("firmware size is not multiple of 32 bits: %zu",
608 fw->size);
609 ret = -EILSEQ;
610 goto out;
611 }
612
613 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300614 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300615
616 if (!wl->fw) {
617 wl1271_error("could not allocate memory for the firmware");
618 ret = -ENOMEM;
619 goto out;
620 }
621
622 memcpy(wl->fw, fw->data, wl->fw_len);
623
624 ret = 0;
625
626out:
627 release_firmware(fw);
628
629 return ret;
630}
631
632static int wl1271_fetch_nvs(struct wl1271 *wl)
633{
634 const struct firmware *fw;
635 int ret;
636
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200637 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638
639 if (ret < 0) {
640 wl1271_error("could not get nvs file: %d", ret);
641 return ret;
642 }
643
Julia Lawall929ebd32010-05-15 23:16:39 +0200644 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645
646 if (!wl->nvs) {
647 wl1271_error("could not allocate memory for the nvs file");
648 ret = -ENOMEM;
649 goto out;
650 }
651
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200652 wl->nvs_len = fw->size;
653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654out:
655 release_firmware(fw);
656
657 return ret;
658}
659
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200660static void wl1271_recovery_work(struct work_struct *work)
661{
662 struct wl1271 *wl =
663 container_of(work, struct wl1271, recovery_work);
664
665 mutex_lock(&wl->mutex);
666
667 if (wl->state != WL1271_STATE_ON)
668 goto out;
669
670 wl1271_info("Hardware recovery in progress.");
671
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200672 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
673 ieee80211_connection_loss(wl->vif);
674
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200675 /* reboot the chipset */
676 __wl1271_op_remove_interface(wl);
677 ieee80211_restart_hw(wl->hw);
678
679out:
680 mutex_unlock(&wl->mutex);
681}
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683static void wl1271_fw_wakeup(struct wl1271 *wl)
684{
685 u32 elp_reg;
686
687 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300688 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689}
690
691static int wl1271_setup(struct wl1271 *wl)
692{
693 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
694 if (!wl->fw_status)
695 return -ENOMEM;
696
697 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
698 if (!wl->tx_res_if) {
699 kfree(wl->fw_status);
700 return -ENOMEM;
701 }
702
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300703 return 0;
704}
705
706static int wl1271_chip_wakeup(struct wl1271 *wl)
707{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300708 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709 int ret = 0;
710
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200711 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200712 ret = wl1271_power_on(wl);
713 if (ret < 0)
714 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200716 wl1271_io_reset(wl);
717 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718
719 /* We don't need a real memory partition here, because we only want
720 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300721 memset(&partition, 0, sizeof(partition));
722 partition.reg.start = REGISTERS_BASE;
723 partition.reg.size = REGISTERS_DOWN_SIZE;
724 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725
726 /* ELP module wake up */
727 wl1271_fw_wakeup(wl);
728
729 /* whal_FwCtrl_BootSm() */
730
731 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200732 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
734 /* 1. check if chip id is valid */
735
736 switch (wl->chip.id) {
737 case CHIP_ID_1271_PG10:
738 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
739 wl->chip.id);
740
741 ret = wl1271_setup(wl);
742 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200743 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 break;
745 case CHIP_ID_1271_PG20:
746 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
747 wl->chip.id);
748
749 ret = wl1271_setup(wl);
750 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200751 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752 break;
753 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200754 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300755 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200756 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757 }
758
759 if (wl->fw == NULL) {
760 ret = wl1271_fetch_firmware(wl);
761 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200762 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763 }
764
765 /* No NVS from netlink, try to get it from the filesystem */
766 if (wl->nvs == NULL) {
767 ret = wl1271_fetch_nvs(wl);
768 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200769 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 }
771
772out:
773 return ret;
774}
775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776int wl1271_plt_start(struct wl1271 *wl)
777{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200778 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 int ret;
780
781 mutex_lock(&wl->mutex);
782
783 wl1271_notice("power up");
784
785 if (wl->state != WL1271_STATE_OFF) {
786 wl1271_error("cannot go into PLT state because not "
787 "in off state: %d", wl->state);
788 ret = -EBUSY;
789 goto out;
790 }
791
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200792 while (retries) {
793 retries--;
794 ret = wl1271_chip_wakeup(wl);
795 if (ret < 0)
796 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200798 ret = wl1271_boot(wl);
799 if (ret < 0)
800 goto power_off;
801
802 ret = wl1271_plt_init(wl);
803 if (ret < 0)
804 goto irq_disable;
805
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200806 wl->state = WL1271_STATE_PLT;
807 wl1271_notice("firmware booted in PLT mode (%s)",
808 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300809 goto out;
810
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200811irq_disable:
812 wl1271_disable_interrupts(wl);
813 mutex_unlock(&wl->mutex);
814 /* Unlocking the mutex in the middle of handling is
815 inherently unsafe. In this case we deem it safe to do,
816 because we need to let any possibly pending IRQ out of
817 the system (and while we are WL1271_STATE_OFF the IRQ
818 work function will not do anything.) Also, any other
819 possible concurrent operations will fail due to the
820 current state, hence the wl1271 struct should be safe. */
821 cancel_work_sync(&wl->irq_work);
822 mutex_lock(&wl->mutex);
823power_off:
824 wl1271_power_off(wl);
825 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200827 wl1271_error("firmware boot in PLT mode failed despite %d retries",
828 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829out:
830 mutex_unlock(&wl->mutex);
831
832 return ret;
833}
834
835int wl1271_plt_stop(struct wl1271 *wl)
836{
837 int ret = 0;
838
839 mutex_lock(&wl->mutex);
840
841 wl1271_notice("power down");
842
843 if (wl->state != WL1271_STATE_PLT) {
844 wl1271_error("cannot power down because not in PLT "
845 "state: %d", wl->state);
846 ret = -EBUSY;
847 goto out;
848 }
849
850 wl1271_disable_interrupts(wl);
851 wl1271_power_off(wl);
852
853 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300854 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300855
856out:
857 mutex_unlock(&wl->mutex);
858
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200859 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200860 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200861
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 return ret;
863}
864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
866{
867 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200868 struct ieee80211_conf *conf = &hw->conf;
869 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
870 struct ieee80211_sta *sta = txinfo->control.sta;
871 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872
Shahar Levi18357852010-10-13 16:09:41 +0200873 /*
874 * peek into the rates configured in the STA entry.
875 * The rates set after connection stage, The first block only BG sets:
876 * the compare is for bit 0-16 of sta_rate_set. The second block add
877 * HT rates in case of HT supported.
878 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200879 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200880 if (sta &&
881 (sta->supp_rates[conf->channel->band] !=
882 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200883 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
884 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
885 }
Shahar Levi18357852010-10-13 16:09:41 +0200886
Shahar Levi00d20102010-11-08 11:20:10 +0000887#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200888 if (sta &&
889 sta->ht_cap.ht_supported &&
890 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
891 sta->ht_cap.mcs.rx_mask[0])) {
892 /* Clean MCS bits before setting them */
893 wl->sta_rate_set &= HW_BG_RATES_MASK;
894 wl->sta_rate_set |=
895 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
896 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
897 }
898#endif
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200899 spin_unlock_irqrestore(&wl->wl_lock, flags);
900
901 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 skb_queue_tail(&wl->tx_queue, skb);
903
904 /*
905 * The chip specific setup must run before the first TX packet -
906 * before that, the tx_work will not be initialized!
907 */
908
Ido Yariva5225502010-10-12 14:49:10 +0200909 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
910 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
912 /*
913 * The workqueue is slow to process the tx_queue and we need stop
914 * the queue here, otherwise the queue will get too long.
915 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200916 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
917 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200919 spin_lock_irqsave(&wl->wl_lock, flags);
920 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200921 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200922 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923 }
924
925 return NETDEV_TX_OK;
926}
927
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300928static struct notifier_block wl1271_dev_notifier = {
929 .notifier_call = wl1271_dev_notify,
930};
931
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932static int wl1271_op_start(struct ieee80211_hw *hw)
933{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200934 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
935
936 /*
937 * We have to delay the booting of the hardware because
938 * we need to know the local MAC address before downloading and
939 * initializing the firmware. The MAC address cannot be changed
940 * after boot, and without the proper MAC address, the firmware
941 * will not function properly.
942 *
943 * The MAC address is first known when the corresponding interface
944 * is added. That is where we will initialize the hardware.
945 */
946
947 return 0;
948}
949
950static void wl1271_op_stop(struct ieee80211_hw *hw)
951{
952 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
953}
954
955static int wl1271_op_add_interface(struct ieee80211_hw *hw,
956 struct ieee80211_vif *vif)
957{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400959 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200960 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +0200962 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200964 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
965 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966
967 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200968 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +0200969 wl1271_debug(DEBUG_MAC80211,
970 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200971 ret = -EBUSY;
972 goto out;
973 }
974
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200975 switch (vif->type) {
976 case NL80211_IFTYPE_STATION:
977 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200978 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200979 break;
980 case NL80211_IFTYPE_ADHOC:
981 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200982 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200983 break;
984 default:
985 ret = -EOPNOTSUPP;
986 goto out;
987 }
988
989 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990
991 if (wl->state != WL1271_STATE_OFF) {
992 wl1271_error("cannot start because not in off state: %d",
993 wl->state);
994 ret = -EBUSY;
995 goto out;
996 }
997
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200998 while (retries) {
999 retries--;
1000 ret = wl1271_chip_wakeup(wl);
1001 if (ret < 0)
1002 goto power_off;
1003
1004 ret = wl1271_boot(wl);
1005 if (ret < 0)
1006 goto power_off;
1007
1008 ret = wl1271_hw_init(wl);
1009 if (ret < 0)
1010 goto irq_disable;
1011
Eliad Peller71125ab2010-10-28 21:46:43 +02001012 booted = true;
1013 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001015irq_disable:
1016 wl1271_disable_interrupts(wl);
1017 mutex_unlock(&wl->mutex);
1018 /* Unlocking the mutex in the middle of handling is
1019 inherently unsafe. In this case we deem it safe to do,
1020 because we need to let any possibly pending IRQ out of
1021 the system (and while we are WL1271_STATE_OFF the IRQ
1022 work function will not do anything.) Also, any other
1023 possible concurrent operations will fail due to the
1024 current state, hence the wl1271 struct should be safe. */
1025 cancel_work_sync(&wl->irq_work);
1026 mutex_lock(&wl->mutex);
1027power_off:
1028 wl1271_power_off(wl);
1029 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030
Eliad Peller71125ab2010-10-28 21:46:43 +02001031 if (!booted) {
1032 wl1271_error("firmware boot failed despite %d retries",
1033 WL1271_BOOT_RETRIES);
1034 goto out;
1035 }
1036
1037 wl->vif = vif;
1038 wl->state = WL1271_STATE_ON;
1039 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1040
1041 /* update hw/fw version info in wiphy struct */
1042 wiphy->hw_version = wl->chip.id;
1043 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1044 sizeof(wiphy->fw_version));
1045
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001046out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 mutex_unlock(&wl->mutex);
1048
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001049 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001050 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 return ret;
1053}
1054
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001055static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 int i;
1058
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001059 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001061 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001063 list_del(&wl->list);
1064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065 WARN_ON(wl->state != WL1271_STATE_ON);
1066
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001067 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001068 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001069 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001070
Luciano Coelho08688d62010-07-08 17:50:07 +03001071 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001072 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1073 kfree(wl->scan.scanned_ch);
1074 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001075 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001076 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 }
1078
1079 wl->state = WL1271_STATE_OFF;
1080
1081 wl1271_disable_interrupts(wl);
1082
1083 mutex_unlock(&wl->mutex);
1084
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001085 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 cancel_work_sync(&wl->irq_work);
1087 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001088 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001089 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090
1091 mutex_lock(&wl->mutex);
1092
1093 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001094 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 wl1271_power_off(wl);
1096
1097 memset(wl->bssid, 0, ETH_ALEN);
1098 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1099 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001101 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001102 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103
1104 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001105 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1107 wl->tx_blocks_available = 0;
1108 wl->tx_results_count = 0;
1109 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001110 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001111 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 wl->time_offset = 0;
1113 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001114 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1115 wl->sta_rate_set = 0;
1116 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001117 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001118 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120 for (i = 0; i < NUM_TX_QUEUES; i++)
1121 wl->tx_blocks_freed[i] = 0;
1122
1123 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001124
1125 kfree(wl->fw_status);
1126 wl->fw_status = NULL;
1127 kfree(wl->tx_res_if);
1128 wl->tx_res_if = NULL;
1129 kfree(wl->target_mem_map);
1130 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001131}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001132
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001133static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1134 struct ieee80211_vif *vif)
1135{
1136 struct wl1271 *wl = hw->priv;
1137
1138 mutex_lock(&wl->mutex);
1139 WARN_ON(wl->vif != vif);
1140 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001142
1143 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001144}
1145
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001146static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1147{
1148 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1149 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1150
1151 /* combine requested filters with current filter config */
1152 filters = wl->filters | filters;
1153
1154 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1155
1156 if (filters & FIF_PROMISC_IN_BSS) {
1157 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1158 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1159 wl->rx_config |= CFG_BSSID_FILTER_EN;
1160 }
1161 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1162 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1163 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1164 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1165 }
1166 if (filters & FIF_OTHER_BSS) {
1167 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1168 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1169 }
1170 if (filters & FIF_CONTROL) {
1171 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1172 wl->rx_filter |= CFG_RX_CTL_EN;
1173 }
1174 if (filters & FIF_FCSFAIL) {
1175 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1176 wl->rx_filter |= CFG_RX_FCS_ERROR;
1177 }
1178}
1179
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001180static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001181{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001182 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001183 /* we need to use a dummy BSSID for now */
1184 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1185 0xad, 0xbe, 0xef };
1186
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001187 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1188
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001189 /* pass through frames from all BSS */
1190 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1191
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001192 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001193 if (ret < 0)
1194 goto out;
1195
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001196 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001197
1198out:
1199 return ret;
1200}
1201
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001202static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001203{
1204 int ret;
1205
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001206 /*
1207 * One of the side effects of the JOIN command is that is clears
1208 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1209 * to a WPA/WPA2 access point will therefore kill the data-path.
1210 * Currently there is no supported scenario for JOIN during
1211 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1212 * must be handled somehow.
1213 *
1214 */
1215 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1216 wl1271_info("JOIN while associated.");
1217
1218 if (set_assoc)
1219 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1220
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001221 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1222 if (ret < 0)
1223 goto out;
1224
1225 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1226
1227 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1228 goto out;
1229
1230 /*
1231 * The join command disable the keep-alive mode, shut down its process,
1232 * and also clear the template config, so we need to reset it all after
1233 * the join. The acx_aid starts the keep-alive process, and the order
1234 * of the commands below is relevant.
1235 */
1236 ret = wl1271_acx_keep_alive_mode(wl, true);
1237 if (ret < 0)
1238 goto out;
1239
1240 ret = wl1271_acx_aid(wl, wl->aid);
1241 if (ret < 0)
1242 goto out;
1243
1244 ret = wl1271_cmd_build_klv_null_data(wl);
1245 if (ret < 0)
1246 goto out;
1247
1248 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1249 ACX_KEEP_ALIVE_TPL_VALID);
1250 if (ret < 0)
1251 goto out;
1252
1253out:
1254 return ret;
1255}
1256
1257static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001258{
1259 int ret;
1260
1261 /* to stop listening to a channel, we disconnect */
1262 ret = wl1271_cmd_disconnect(wl);
1263 if (ret < 0)
1264 goto out;
1265
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001266 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001267 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001268
1269 /* stop filterting packets based on bssid */
1270 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001271
1272out:
1273 return ret;
1274}
1275
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001276static void wl1271_set_band_rate(struct wl1271 *wl)
1277{
1278 if (wl->band == IEEE80211_BAND_2GHZ)
1279 wl->basic_rate_set = wl->conf.tx.basic_rate;
1280 else
1281 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1282}
1283
1284static u32 wl1271_min_rate_get(struct wl1271 *wl)
1285{
1286 int i;
1287 u32 rate = 0;
1288
1289 if (!wl->basic_rate_set) {
1290 WARN_ON(1);
1291 wl->basic_rate_set = wl->conf.tx.basic_rate;
1292 }
1293
1294 for (i = 0; !rate; i++) {
1295 if ((wl->basic_rate_set >> i) & 0x1)
1296 rate = 1 << i;
1297 }
1298
1299 return rate;
1300}
1301
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001302static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1303{
1304 int ret;
1305
1306 if (idle) {
1307 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1308 ret = wl1271_unjoin(wl);
1309 if (ret < 0)
1310 goto out;
1311 }
1312 wl->rate_set = wl1271_min_rate_get(wl);
1313 wl->sta_rate_set = 0;
1314 ret = wl1271_acx_rate_policies(wl);
1315 if (ret < 0)
1316 goto out;
1317 ret = wl1271_acx_keep_alive_config(
1318 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1319 ACX_KEEP_ALIVE_TPL_INVALID);
1320 if (ret < 0)
1321 goto out;
1322 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1323 } else {
1324 /* increment the session counter */
1325 wl->session_counter++;
1326 if (wl->session_counter >= SESSION_COUNTER_MAX)
1327 wl->session_counter = 0;
1328 ret = wl1271_dummy_join(wl);
1329 if (ret < 0)
1330 goto out;
1331 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1332 }
1333
1334out:
1335 return ret;
1336}
1337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1339{
1340 struct wl1271 *wl = hw->priv;
1341 struct ieee80211_conf *conf = &hw->conf;
1342 int channel, ret = 0;
1343
1344 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1345
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001346 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 channel,
1348 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001349 conf->power_level,
1350 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001352 /*
1353 * mac80211 will go to idle nearly immediately after transmitting some
1354 * frames, such as the deauth. To make sure those frames reach the air,
1355 * wait here until the TX queue is fully flushed.
1356 */
1357 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1358 (conf->flags & IEEE80211_CONF_IDLE))
1359 wl1271_tx_flush(wl);
1360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 mutex_lock(&wl->mutex);
1362
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001363 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1364 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001365 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001366 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 ret = wl1271_ps_elp_wakeup(wl, false);
1369 if (ret < 0)
1370 goto out;
1371
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001372 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001373 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1374 ((wl->band != conf->channel->band) ||
1375 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001376 wl->band = conf->channel->band;
1377 wl->channel = channel;
1378
1379 /*
1380 * FIXME: the mac80211 should really provide a fixed rate
1381 * to use here. for now, just use the smallest possible rate
1382 * for the band as a fixed rate for association frames and
1383 * other control messages.
1384 */
1385 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1386 wl1271_set_band_rate(wl);
1387
1388 wl->basic_rate = wl1271_min_rate_get(wl);
1389 ret = wl1271_acx_rate_policies(wl);
1390 if (ret < 0)
1391 wl1271_warning("rate policy for update channel "
1392 "failed %d", ret);
1393
1394 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001395 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001396 if (ret < 0)
1397 wl1271_warning("cmd join to update channel "
1398 "failed %d", ret);
1399 }
1400 }
1401
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001402 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001403 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1404 if (ret < 0)
1405 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406 }
1407
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001408 /*
1409 * if mac80211 changes the PSM mode, make sure the mode is not
1410 * incorrectly changed after the pspoll failure active window.
1411 */
1412 if (changed & IEEE80211_CONF_CHANGE_PS)
1413 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1414
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001415 if (conf->flags & IEEE80211_CONF_PS &&
1416 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1417 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418
1419 /*
1420 * We enter PSM only if we're already associated.
1421 * If we're not, we'll enter it when joining an SSID,
1422 * through the bss_info_changed() hook.
1423 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001424 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001425 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001426 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001427 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001428 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001430 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001431 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001433 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001434
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001435 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001436 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001437 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438 }
1439
1440 if (conf->power_level != wl->power_level) {
1441 ret = wl1271_acx_tx_power(wl, conf->power_level);
1442 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001443 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444
1445 wl->power_level = conf->power_level;
1446 }
1447
1448out_sleep:
1449 wl1271_ps_elp_sleep(wl);
1450
1451out:
1452 mutex_unlock(&wl->mutex);
1453
1454 return ret;
1455}
1456
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001457struct wl1271_filter_params {
1458 bool enabled;
1459 int mc_list_length;
1460 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1461};
1462
Jiri Pirko22bedad2010-04-01 21:22:57 +00001463static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1464 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001465{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001466 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001467 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001468 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001469
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001470 if (unlikely(wl->state == WL1271_STATE_OFF))
1471 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001472
Juuso Oikarinen74441132009-10-13 12:47:53 +03001473 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001474 if (!fp) {
1475 wl1271_error("Out of memory setting filters.");
1476 return 0;
1477 }
1478
1479 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001480 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001481 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1482 fp->enabled = false;
1483 } else {
1484 fp->enabled = true;
1485 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001486 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001487 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001488 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001489 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001490 }
1491
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001492 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001493}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001495#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1496 FIF_ALLMULTI | \
1497 FIF_FCSFAIL | \
1498 FIF_BCN_PRBRESP_PROMISC | \
1499 FIF_CONTROL | \
1500 FIF_OTHER_BSS)
1501
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1503 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001504 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001506 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001508 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509
1510 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1511
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001512 mutex_lock(&wl->mutex);
1513
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001514 *total &= WL1271_SUPPORTED_FILTERS;
1515 changed &= WL1271_SUPPORTED_FILTERS;
1516
1517 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001518 goto out;
1519
1520 ret = wl1271_ps_elp_wakeup(wl, false);
1521 if (ret < 0)
1522 goto out;
1523
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001525 if (*total & FIF_ALLMULTI)
1526 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1527 else if (fp)
1528 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1529 fp->mc_list,
1530 fp->mc_list_length);
1531 if (ret < 0)
1532 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001534 /* determine, whether supported filter values have changed */
1535 if (changed == 0)
1536 goto out_sleep;
1537
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001538 /* configure filters */
1539 wl->filters = *total;
1540 wl1271_configure_filters(wl, 0);
1541
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001542 /* apply configured filters */
1543 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1544 if (ret < 0)
1545 goto out_sleep;
1546
1547out_sleep:
1548 wl1271_ps_elp_sleep(wl);
1549
1550out:
1551 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001552 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553}
1554
1555static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1556 struct ieee80211_vif *vif,
1557 struct ieee80211_sta *sta,
1558 struct ieee80211_key_conf *key_conf)
1559{
1560 struct wl1271 *wl = hw->priv;
1561 const u8 *addr;
1562 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001563 u32 tx_seq_32 = 0;
1564 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565 u8 key_type;
1566
1567 static const u8 bcast_addr[ETH_ALEN] =
1568 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1569
1570 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1571
1572 addr = sta ? sta->addr : bcast_addr;
1573
1574 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1575 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1576 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001577 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 key_conf->keylen, key_conf->flags);
1579 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1580
1581 if (is_zero_ether_addr(addr)) {
1582 /* We dont support TX only encryption */
1583 ret = -EOPNOTSUPP;
1584 goto out;
1585 }
1586
1587 mutex_lock(&wl->mutex);
1588
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001589 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1590 ret = -EAGAIN;
1591 goto out_unlock;
1592 }
1593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594 ret = wl1271_ps_elp_wakeup(wl, false);
1595 if (ret < 0)
1596 goto out_unlock;
1597
Johannes Berg97359d12010-08-10 09:46:38 +02001598 switch (key_conf->cipher) {
1599 case WLAN_CIPHER_SUITE_WEP40:
1600 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601 key_type = KEY_WEP;
1602
1603 key_conf->hw_key_idx = key_conf->keyidx;
1604 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001605 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 key_type = KEY_TKIP;
1607
1608 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001609 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1610 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001612 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001613 key_type = KEY_AES;
1614
1615 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001616 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1617 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001618 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001619 case WL1271_CIPHER_SUITE_GEM:
1620 key_type = KEY_GEM;
1621 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1622 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1623 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001624 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001625 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001626
1627 ret = -EOPNOTSUPP;
1628 goto out_sleep;
1629 }
1630
1631 switch (cmd) {
1632 case SET_KEY:
1633 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1634 key_conf->keyidx, key_type,
1635 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001636 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001637 if (ret < 0) {
1638 wl1271_error("Could not add or replace key");
1639 goto out_sleep;
1640 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001641
1642 /* the default WEP key needs to be configured at least once */
1643 if (key_type == KEY_WEP) {
1644 ret = wl1271_cmd_set_default_wep_key(wl,
1645 wl->default_key);
1646 if (ret < 0)
1647 goto out_sleep;
1648 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649 break;
1650
1651 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001652 /* The wl1271 does not allow to remove unicast keys - they
1653 will be cleared automatically on next CMD_JOIN. Ignore the
1654 request silently, as we dont want the mac80211 to emit
1655 an error message. */
1656 if (!is_broadcast_ether_addr(addr))
1657 break;
1658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1660 key_conf->keyidx, key_type,
1661 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001662 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663 if (ret < 0) {
1664 wl1271_error("Could not remove key");
1665 goto out_sleep;
1666 }
1667 break;
1668
1669 default:
1670 wl1271_error("Unsupported key cmd 0x%x", cmd);
1671 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672 break;
1673 }
1674
1675out_sleep:
1676 wl1271_ps_elp_sleep(wl);
1677
1678out_unlock:
1679 mutex_unlock(&wl->mutex);
1680
1681out:
1682 return ret;
1683}
1684
1685static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001686 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 struct cfg80211_scan_request *req)
1688{
1689 struct wl1271 *wl = hw->priv;
1690 int ret;
1691 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001692 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693
1694 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1695
1696 if (req->n_ssids) {
1697 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001698 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699 }
1700
1701 mutex_lock(&wl->mutex);
1702
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001703 if (wl->state == WL1271_STATE_OFF) {
1704 /*
1705 * We cannot return -EBUSY here because cfg80211 will expect
1706 * a call to ieee80211_scan_completed if we do - in this case
1707 * there won't be any call.
1708 */
1709 ret = -EAGAIN;
1710 goto out;
1711 }
1712
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001713 ret = wl1271_ps_elp_wakeup(wl, false);
1714 if (ret < 0)
1715 goto out;
1716
Luciano Coelho5924f892010-08-04 03:46:22 +03001717 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718
1719 wl1271_ps_elp_sleep(wl);
1720
1721out:
1722 mutex_unlock(&wl->mutex);
1723
1724 return ret;
1725}
1726
1727static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1728{
1729 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001730 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731
1732 mutex_lock(&wl->mutex);
1733
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001734 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1735 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001736 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001737 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739 ret = wl1271_ps_elp_wakeup(wl, false);
1740 if (ret < 0)
1741 goto out;
1742
1743 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1744 if (ret < 0)
1745 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1746
1747 wl1271_ps_elp_sleep(wl);
1748
1749out:
1750 mutex_unlock(&wl->mutex);
1751
1752 return ret;
1753}
1754
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001755static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1756{
1757 u8 *ptr = beacon->data +
1758 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1759
1760 /* find the location of the ssid in the beacon */
1761 while (ptr < beacon->data + beacon->len) {
1762 if (ptr[0] == WLAN_EID_SSID) {
1763 wl->ssid_len = ptr[1];
1764 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1765 return;
1766 }
1767 ptr += ptr[1];
1768 }
1769 wl1271_error("ad-hoc beacon template has no SSID!\n");
1770}
1771
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1773 struct ieee80211_vif *vif,
1774 struct ieee80211_bss_conf *bss_conf,
1775 u32 changed)
1776{
1777 enum wl1271_cmd_ps_mode mode;
1778 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001779 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001780 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001781 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782 int ret;
1783
1784 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1785
1786 mutex_lock(&wl->mutex);
1787
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001788 if (unlikely(wl->state == WL1271_STATE_OFF))
1789 goto out;
1790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 ret = wl1271_ps_elp_wakeup(wl, false);
1792 if (ret < 0)
1793 goto out;
1794
Eliad Peller9ee82d52010-09-19 18:55:09 +02001795 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001796 (wl->bss_type == BSS_TYPE_IBSS)) {
1797 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1798 bss_conf->beacon_int);
1799
1800 wl->beacon_int = bss_conf->beacon_int;
1801 do_join = true;
1802 }
1803
Eliad Peller9ee82d52010-09-19 18:55:09 +02001804 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001805 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001806 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1807
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001808 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1809
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001810 if (beacon) {
1811 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001812
1813 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001814 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1815 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001816 beacon->len, 0,
1817 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001818
1819 if (ret < 0) {
1820 dev_kfree_skb(beacon);
1821 goto out_sleep;
1822 }
1823
1824 hdr = (struct ieee80211_hdr *) beacon->data;
1825 hdr->frame_control = cpu_to_le16(
1826 IEEE80211_FTYPE_MGMT |
1827 IEEE80211_STYPE_PROBE_RESP);
1828
1829 ret = wl1271_cmd_template_set(wl,
1830 CMD_TEMPL_PROBE_RESPONSE,
1831 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001832 beacon->len, 0,
1833 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001834 dev_kfree_skb(beacon);
1835 if (ret < 0)
1836 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001837
1838 /* Need to update the SSID (for filtering etc) */
1839 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001840 }
1841 }
1842
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001843 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1844 (wl->bss_type == BSS_TYPE_IBSS)) {
1845 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1846 bss_conf->enable_beacon ? "enabled" : "disabled");
1847
1848 if (bss_conf->enable_beacon)
1849 wl->set_bss_type = BSS_TYPE_IBSS;
1850 else
1851 wl->set_bss_type = BSS_TYPE_STA_BSS;
1852 do_join = true;
1853 }
1854
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001855 if (changed & BSS_CHANGED_CQM) {
1856 bool enable = false;
1857 if (bss_conf->cqm_rssi_thold)
1858 enable = true;
1859 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1860 bss_conf->cqm_rssi_thold,
1861 bss_conf->cqm_rssi_hyst);
1862 if (ret < 0)
1863 goto out;
1864 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1865 }
1866
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001867 if ((changed & BSS_CHANGED_BSSID) &&
1868 /*
1869 * Now we know the correct bssid, so we send a new join command
1870 * and enable the BSSID filter
1871 */
1872 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001873 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001874
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001875 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001876 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001877 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001878
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001879 ret = wl1271_build_qos_null_data(wl);
1880 if (ret < 0)
1881 goto out_sleep;
1882
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001883 /* filter out all packets not from this BSSID */
1884 wl1271_configure_filters(wl, 0);
1885
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001886 /* Need to update the BSSID (for filtering etc) */
1887 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001888 }
1889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001890 if (changed & BSS_CHANGED_ASSOC) {
1891 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001892 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001893 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001894 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001896 wl->ps_poll_failures = 0;
1897
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001898 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001899 * use basic rates from AP, and determine lowest rate
1900 * to use with control frames.
1901 */
1902 rates = bss_conf->basic_rates;
1903 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1904 rates);
1905 wl->basic_rate = wl1271_min_rate_get(wl);
1906 ret = wl1271_acx_rate_policies(wl);
1907 if (ret < 0)
1908 goto out_sleep;
1909
1910 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001911 * with wl1271, we don't need to update the
1912 * beacon_int and dtim_period, because the firmware
1913 * updates it by itself when the first beacon is
1914 * received after a join.
1915 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1917 if (ret < 0)
1918 goto out_sleep;
1919
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001920 /*
1921 * The SSID is intentionally set to NULL here - the
1922 * firmware will set the probe request with a
1923 * broadcast SSID regardless of what we set in the
1924 * template.
1925 */
1926 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1927 NULL, 0, wl->band);
1928
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001929 /* enable the connection monitoring feature */
1930 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 if (ret < 0)
1932 goto out_sleep;
1933
1934 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001935 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1936 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001938 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001939 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001940 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 if (ret < 0)
1942 goto out_sleep;
1943 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001944 } else {
1945 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001946 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001947 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001948 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001949
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001950 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001951 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001952
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001953 /* revert back to minimum rates for the current band */
1954 wl1271_set_band_rate(wl);
1955 wl->basic_rate = wl1271_min_rate_get(wl);
1956 ret = wl1271_acx_rate_policies(wl);
1957 if (ret < 0)
1958 goto out_sleep;
1959
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001960 /* disable connection monitor features */
1961 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001962
1963 /* Disable the keep-alive feature */
1964 ret = wl1271_acx_keep_alive_mode(wl, false);
1965
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001966 if (ret < 0)
1967 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001969
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972 if (changed & BSS_CHANGED_ERP_SLOT) {
1973 if (bss_conf->use_short_slot)
1974 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1975 else
1976 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1977 if (ret < 0) {
1978 wl1271_warning("Set slot time failed %d", ret);
1979 goto out_sleep;
1980 }
1981 }
1982
1983 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1984 if (bss_conf->use_short_preamble)
1985 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1986 else
1987 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1988 }
1989
1990 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1991 if (bss_conf->use_cts_prot)
1992 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1993 else
1994 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1995 if (ret < 0) {
1996 wl1271_warning("Set ctsprotect failed %d", ret);
1997 goto out_sleep;
1998 }
1999 }
2000
Shahar Levi18357852010-10-13 16:09:41 +02002001 /*
2002 * Takes care of: New association with HT enable,
2003 * HT information change in beacon.
2004 */
2005 if (sta &&
2006 (changed & BSS_CHANGED_HT) &&
2007 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2008 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2009 if (ret < 0) {
2010 wl1271_warning("Set ht cap true failed %d", ret);
2011 goto out_sleep;
2012 }
2013 ret = wl1271_acx_set_ht_information(wl,
2014 bss_conf->ht_operation_mode);
2015 if (ret < 0) {
2016 wl1271_warning("Set ht information failed %d", ret);
2017 goto out_sleep;
2018 }
2019 }
2020 /*
2021 * Takes care of: New association without HT,
2022 * Disassociation.
2023 */
2024 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2025 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2026 if (ret < 0) {
2027 wl1271_warning("Set ht cap false failed %d", ret);
2028 goto out_sleep;
2029 }
2030 }
2031
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002032 if (changed & BSS_CHANGED_ARP_FILTER) {
2033 __be32 addr = bss_conf->arp_addr_list[0];
2034 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2035
2036 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
2037 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
2038 else
2039 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
2040
2041 if (ret < 0)
2042 goto out_sleep;
2043 }
2044
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002045 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002046 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002047 if (ret < 0) {
2048 wl1271_warning("cmd join failed %d", ret);
2049 goto out_sleep;
2050 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002051 }
2052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053out_sleep:
2054 wl1271_ps_elp_sleep(wl);
2055
2056out:
2057 mutex_unlock(&wl->mutex);
2058}
2059
Kalle Valoc6999d82010-02-18 13:25:41 +02002060static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2061 const struct ieee80211_tx_queue_params *params)
2062{
2063 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002064 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002065 int ret;
2066
2067 mutex_lock(&wl->mutex);
2068
2069 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2070
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002071 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2072 ret = -EAGAIN;
2073 goto out;
2074 }
2075
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002076 ret = wl1271_ps_elp_wakeup(wl, false);
2077 if (ret < 0)
2078 goto out;
2079
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002080 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002081 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2082 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002083 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002084 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002085 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002086
Kalle Valo4695dc92010-03-18 12:26:38 +02002087 if (params->uapsd)
2088 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2089 else
2090 ps_scheme = CONF_PS_SCHEME_LEGACY;
2091
Kalle Valoc6999d82010-02-18 13:25:41 +02002092 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2093 CONF_CHANNEL_TYPE_EDCF,
2094 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002095 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002096 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002097 goto out_sleep;
2098
2099out_sleep:
2100 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002101
2102out:
2103 mutex_unlock(&wl->mutex);
2104
2105 return ret;
2106}
2107
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002108static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2109{
2110
2111 struct wl1271 *wl = hw->priv;
2112 u64 mactime = ULLONG_MAX;
2113 int ret;
2114
2115 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2116
2117 mutex_lock(&wl->mutex);
2118
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002119 if (unlikely(wl->state == WL1271_STATE_OFF))
2120 goto out;
2121
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002122 ret = wl1271_ps_elp_wakeup(wl, false);
2123 if (ret < 0)
2124 goto out;
2125
2126 ret = wl1271_acx_tsf_info(wl, &mactime);
2127 if (ret < 0)
2128 goto out_sleep;
2129
2130out_sleep:
2131 wl1271_ps_elp_sleep(wl);
2132
2133out:
2134 mutex_unlock(&wl->mutex);
2135 return mactime;
2136}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137
John W. Linvilleece550d2010-07-28 16:41:06 -04002138static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2139 struct survey_info *survey)
2140{
2141 struct wl1271 *wl = hw->priv;
2142 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002143
John W. Linvilleece550d2010-07-28 16:41:06 -04002144 if (idx != 0)
2145 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002146
John W. Linvilleece550d2010-07-28 16:41:06 -04002147 survey->channel = conf->channel;
2148 survey->filled = SURVEY_INFO_NOISE_DBM;
2149 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002150
John W. Linvilleece550d2010-07-28 16:41:06 -04002151 return 0;
2152}
2153
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154/* can't be const, mac80211 writes to this */
2155static struct ieee80211_rate wl1271_rates[] = {
2156 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002157 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2158 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002160 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2161 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2163 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002164 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2165 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2167 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002168 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2169 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2171 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002172 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2173 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002175 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2176 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002178 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2179 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002181 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2182 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002184 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2185 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002187 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2188 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002190 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2191 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002193 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2194 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195};
2196
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002197/*
2198 * Can't be const, mac80211 writes to this. The order of the channels here
2199 * is designed to improve scanning.
2200 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002202 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002203 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002204 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002205 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002206 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2207 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2208 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2209 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2210 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2211 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2212 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2213 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2214 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215};
2216
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002217/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002218static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002219 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002220 7, /* CONF_HW_RXTX_RATE_MCS7 */
2221 6, /* CONF_HW_RXTX_RATE_MCS6 */
2222 5, /* CONF_HW_RXTX_RATE_MCS5 */
2223 4, /* CONF_HW_RXTX_RATE_MCS4 */
2224 3, /* CONF_HW_RXTX_RATE_MCS3 */
2225 2, /* CONF_HW_RXTX_RATE_MCS2 */
2226 1, /* CONF_HW_RXTX_RATE_MCS1 */
2227 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002228
2229 11, /* CONF_HW_RXTX_RATE_54 */
2230 10, /* CONF_HW_RXTX_RATE_48 */
2231 9, /* CONF_HW_RXTX_RATE_36 */
2232 8, /* CONF_HW_RXTX_RATE_24 */
2233
2234 /* TI-specific rate */
2235 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2236
2237 7, /* CONF_HW_RXTX_RATE_18 */
2238 6, /* CONF_HW_RXTX_RATE_12 */
2239 3, /* CONF_HW_RXTX_RATE_11 */
2240 5, /* CONF_HW_RXTX_RATE_9 */
2241 4, /* CONF_HW_RXTX_RATE_6 */
2242 2, /* CONF_HW_RXTX_RATE_5_5 */
2243 1, /* CONF_HW_RXTX_RATE_2 */
2244 0 /* CONF_HW_RXTX_RATE_1 */
2245};
2246
Shahar Levie8b03a22010-10-13 16:09:39 +02002247/* 11n STA capabilities */
2248#define HW_RX_HIGHEST_RATE 72
2249
Shahar Levi00d20102010-11-08 11:20:10 +00002250#ifdef CONFIG_WL12XX_HT
2251#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002252 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2253 .ht_supported = true, \
2254 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2255 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2256 .mcs = { \
2257 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2258 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2259 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2260 }, \
2261}
Shahar Levi18357852010-10-13 16:09:41 +02002262#else
Shahar Levi00d20102010-11-08 11:20:10 +00002263#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002264 .ht_supported = false, \
2265}
2266#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002268/* can't be const, mac80211 writes to this */
2269static struct ieee80211_supported_band wl1271_band_2ghz = {
2270 .channels = wl1271_channels,
2271 .n_channels = ARRAY_SIZE(wl1271_channels),
2272 .bitrates = wl1271_rates,
2273 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002274 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002275};
2276
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002277/* 5 GHz data rates for WL1273 */
2278static struct ieee80211_rate wl1271_rates_5ghz[] = {
2279 { .bitrate = 60,
2280 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2281 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2282 { .bitrate = 90,
2283 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2284 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2285 { .bitrate = 120,
2286 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2287 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2288 { .bitrate = 180,
2289 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2290 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2291 { .bitrate = 240,
2292 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2293 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2294 { .bitrate = 360,
2295 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2296 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2297 { .bitrate = 480,
2298 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2299 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2300 { .bitrate = 540,
2301 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2302 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2303};
2304
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002305/*
2306 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2307 * The order of the channels here is designed to improve scanning.
2308 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002309static struct ieee80211_channel wl1271_channels_5ghz[] = {
2310 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002311 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002312 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002313 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002314 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002315 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002316 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002317 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002318 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002319 { .hw_value = 184, .center_freq = 4920},
2320 { .hw_value = 189, .center_freq = 4945},
2321 { .hw_value = 9, .center_freq = 5045},
2322 { .hw_value = 36, .center_freq = 5180},
2323 { .hw_value = 46, .center_freq = 5230},
2324 { .hw_value = 64, .center_freq = 5320},
2325 { .hw_value = 116, .center_freq = 5580},
2326 { .hw_value = 136, .center_freq = 5680},
2327 { .hw_value = 192, .center_freq = 4960},
2328 { .hw_value = 11, .center_freq = 5055},
2329 { .hw_value = 38, .center_freq = 5190},
2330 { .hw_value = 48, .center_freq = 5240},
2331 { .hw_value = 100, .center_freq = 5500},
2332 { .hw_value = 120, .center_freq = 5600},
2333 { .hw_value = 140, .center_freq = 5700},
2334 { .hw_value = 185, .center_freq = 4925},
2335 { .hw_value = 196, .center_freq = 4980},
2336 { .hw_value = 12, .center_freq = 5060},
2337 { .hw_value = 40, .center_freq = 5200},
2338 { .hw_value = 52, .center_freq = 5260},
2339 { .hw_value = 104, .center_freq = 5520},
2340 { .hw_value = 124, .center_freq = 5620},
2341 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002342 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002343 { .hw_value = 187, .center_freq = 4935},
2344 { .hw_value = 7, .center_freq = 5035},
2345 { .hw_value = 16, .center_freq = 5080},
2346 { .hw_value = 42, .center_freq = 5210},
2347 { .hw_value = 56, .center_freq = 5280},
2348 { .hw_value = 108, .center_freq = 5540},
2349 { .hw_value = 128, .center_freq = 5640},
2350 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002351 { .hw_value = 165, .center_freq = 5825},
2352};
2353
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002354/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002355static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002356 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002357 7, /* CONF_HW_RXTX_RATE_MCS7 */
2358 6, /* CONF_HW_RXTX_RATE_MCS6 */
2359 5, /* CONF_HW_RXTX_RATE_MCS5 */
2360 4, /* CONF_HW_RXTX_RATE_MCS4 */
2361 3, /* CONF_HW_RXTX_RATE_MCS3 */
2362 2, /* CONF_HW_RXTX_RATE_MCS2 */
2363 1, /* CONF_HW_RXTX_RATE_MCS1 */
2364 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002365
2366 7, /* CONF_HW_RXTX_RATE_54 */
2367 6, /* CONF_HW_RXTX_RATE_48 */
2368 5, /* CONF_HW_RXTX_RATE_36 */
2369 4, /* CONF_HW_RXTX_RATE_24 */
2370
2371 /* TI-specific rate */
2372 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2373
2374 3, /* CONF_HW_RXTX_RATE_18 */
2375 2, /* CONF_HW_RXTX_RATE_12 */
2376 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2377 1, /* CONF_HW_RXTX_RATE_9 */
2378 0, /* CONF_HW_RXTX_RATE_6 */
2379 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2380 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2381 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2382};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002383
2384static struct ieee80211_supported_band wl1271_band_5ghz = {
2385 .channels = wl1271_channels_5ghz,
2386 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2387 .bitrates = wl1271_rates_5ghz,
2388 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002389 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002390};
2391
Tobias Klausera0ea9492010-05-20 10:38:11 +02002392static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002393 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2394 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2395};
2396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002397static const struct ieee80211_ops wl1271_ops = {
2398 .start = wl1271_op_start,
2399 .stop = wl1271_op_stop,
2400 .add_interface = wl1271_op_add_interface,
2401 .remove_interface = wl1271_op_remove_interface,
2402 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002403 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404 .configure_filter = wl1271_op_configure_filter,
2405 .tx = wl1271_op_tx,
2406 .set_key = wl1271_op_set_key,
2407 .hw_scan = wl1271_op_hw_scan,
2408 .bss_info_changed = wl1271_op_bss_info_changed,
2409 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002410 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002411 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002412 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002413 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002414};
2415
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002416
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002417u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002418{
2419 u8 idx;
2420
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002421 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002422
2423 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2424 wl1271_error("Illegal RX rate from HW: %d", rate);
2425 return 0;
2426 }
2427
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002428 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002429 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2430 wl1271_error("Unsupported RX rate from HW: %d", rate);
2431 return 0;
2432 }
2433
2434 return idx;
2435}
2436
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002437static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2438 struct device_attribute *attr,
2439 char *buf)
2440{
2441 struct wl1271 *wl = dev_get_drvdata(dev);
2442 ssize_t len;
2443
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002444 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002445
2446 mutex_lock(&wl->mutex);
2447 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2448 wl->sg_enabled);
2449 mutex_unlock(&wl->mutex);
2450
2451 return len;
2452
2453}
2454
2455static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2456 struct device_attribute *attr,
2457 const char *buf, size_t count)
2458{
2459 struct wl1271 *wl = dev_get_drvdata(dev);
2460 unsigned long res;
2461 int ret;
2462
2463 ret = strict_strtoul(buf, 10, &res);
2464
2465 if (ret < 0) {
2466 wl1271_warning("incorrect value written to bt_coex_mode");
2467 return count;
2468 }
2469
2470 mutex_lock(&wl->mutex);
2471
2472 res = !!res;
2473
2474 if (res == wl->sg_enabled)
2475 goto out;
2476
2477 wl->sg_enabled = res;
2478
2479 if (wl->state == WL1271_STATE_OFF)
2480 goto out;
2481
2482 ret = wl1271_ps_elp_wakeup(wl, false);
2483 if (ret < 0)
2484 goto out;
2485
2486 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2487 wl1271_ps_elp_sleep(wl);
2488
2489 out:
2490 mutex_unlock(&wl->mutex);
2491 return count;
2492}
2493
2494static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2495 wl1271_sysfs_show_bt_coex_state,
2496 wl1271_sysfs_store_bt_coex_state);
2497
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002498static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2499 struct device_attribute *attr,
2500 char *buf)
2501{
2502 struct wl1271 *wl = dev_get_drvdata(dev);
2503 ssize_t len;
2504
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002505 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002506
2507 mutex_lock(&wl->mutex);
2508 if (wl->hw_pg_ver >= 0)
2509 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2510 else
2511 len = snprintf(buf, len, "n/a\n");
2512 mutex_unlock(&wl->mutex);
2513
2514 return len;
2515}
2516
2517static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2518 wl1271_sysfs_show_hw_pg_ver, NULL);
2519
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002520int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521{
2522 int ret;
2523
2524 if (wl->mac80211_registered)
2525 return 0;
2526
2527 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2528
2529 ret = ieee80211_register_hw(wl->hw);
2530 if (ret < 0) {
2531 wl1271_error("unable to register mac80211 hw: %d", ret);
2532 return ret;
2533 }
2534
2535 wl->mac80211_registered = true;
2536
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002537 register_netdevice_notifier(&wl1271_dev_notifier);
2538
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539 wl1271_notice("loaded");
2540
2541 return 0;
2542}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002543EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002545void wl1271_unregister_hw(struct wl1271 *wl)
2546{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002547 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002548 ieee80211_unregister_hw(wl->hw);
2549 wl->mac80211_registered = false;
2550
2551}
2552EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2553
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002554int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002555{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002556 static const u32 cipher_suites[] = {
2557 WLAN_CIPHER_SUITE_WEP40,
2558 WLAN_CIPHER_SUITE_WEP104,
2559 WLAN_CIPHER_SUITE_TKIP,
2560 WLAN_CIPHER_SUITE_CCMP,
2561 WL1271_CIPHER_SUITE_GEM,
2562 };
2563
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002564 /* The tx descriptor buffer and the TKIP space. */
2565 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2566 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567
2568 /* unit us */
2569 /* FIXME: find a proper value */
2570 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002571 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572
2573 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002574 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002575 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002576 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002577 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002578 IEEE80211_HW_CONNECTION_MONITOR |
2579 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002580
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002581 wl->hw->wiphy->cipher_suites = cipher_suites;
2582 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2583
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002584 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2585 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 wl->hw->wiphy->max_scan_ssids = 1;
2587 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002588 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002589
Kalle Valo12bd8942010-03-18 12:26:33 +02002590 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002591 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002592
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002593 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594
2595 return 0;
2596}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002597EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002598
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002600
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002601struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002603 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002604 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002606 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002607 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002608
2609 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2610 if (!hw) {
2611 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002612 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002613 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614 }
2615
Julia Lawall929ebd32010-05-15 23:16:39 +02002616 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002617 if (!plat_dev) {
2618 wl1271_error("could not allocate platform_device");
2619 ret = -ENOMEM;
2620 goto err_plat_alloc;
2621 }
2622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623 wl = hw->priv;
2624 memset(wl, 0, sizeof(*wl));
2625
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002626 INIT_LIST_HEAD(&wl->list);
2627
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002628 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002629 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630
2631 skb_queue_head_init(&wl->tx_queue);
2632
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002633 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002634 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002635 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2636 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2637 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2638 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002639 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002640 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002641 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002642 wl->rx_counter = 0;
2643 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2644 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002645 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002647 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002648 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002649 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2650 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002651 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002652 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002653 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002654 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002655 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002656
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002657 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002658 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659 wl->tx_frames[i] = NULL;
2660
2661 spin_lock_init(&wl->wl_lock);
2662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663 wl->state = WL1271_STATE_OFF;
2664 mutex_init(&wl->mutex);
2665
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002666 /* Apply default driver configuration. */
2667 wl1271_conf_init(wl);
2668
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002669 wl1271_debugfs_init(wl);
2670
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002671 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2672 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2673 if (!wl->aggr_buf) {
2674 ret = -ENOMEM;
2675 goto err_hw;
2676 }
2677
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002678 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002679 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002680 if (ret) {
2681 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002682 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002683 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002684 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002685
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002686 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002687 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002688 if (ret < 0) {
2689 wl1271_error("failed to create sysfs file bt_coex_state");
2690 goto err_platform;
2691 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002692
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002693 /* Create sysfs file to get HW PG version */
2694 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2695 if (ret < 0) {
2696 wl1271_error("failed to create sysfs file hw_pg_ver");
2697 goto err_bt_coex_state;
2698 }
2699
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002700 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002701
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002702err_bt_coex_state:
2703 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2704
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002705err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002706 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002707
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002708err_aggr:
2709 free_pages((unsigned long)wl->aggr_buf, order);
2710
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002711err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002712 wl1271_debugfs_exit(wl);
2713 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002714
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002715err_plat_alloc:
2716 ieee80211_free_hw(hw);
2717
2718err_hw_alloc:
2719
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002720 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002721}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002722EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002723
2724int wl1271_free_hw(struct wl1271 *wl)
2725{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002726 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002727 free_pages((unsigned long)wl->aggr_buf,
2728 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002729 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002730
2731 wl1271_debugfs_exit(wl);
2732
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002733 vfree(wl->fw);
2734 wl->fw = NULL;
2735 kfree(wl->nvs);
2736 wl->nvs = NULL;
2737
2738 kfree(wl->fw_status);
2739 kfree(wl->tx_res_if);
2740
2741 ieee80211_free_hw(wl->hw);
2742
2743 return 0;
2744}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002745EXPORT_SYMBOL_GPL(wl1271_free_hw);
2746
2747MODULE_LICENSE("GPL");
2748MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2749MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");