blob: bec2b3d78782379c98ebf55c7fa2a01c12d64121 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso 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
532 if (intr & WL1271_ACX_INTR_DATA) {
533 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
534
535 /* check for tx results */
536 if (wl->fw_status->tx_results_counter !=
537 (wl->tx_results_count & 0xff))
538 wl1271_tx_complete(wl);
539
Ido Yariva5225502010-10-12 14:49:10 +0200540 /* Check if any tx blocks were freed */
541 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
542 !skb_queue_empty(&wl->tx_queue)) {
543 /*
544 * In order to avoid starvation of the TX path,
545 * call the work function directly.
546 */
547 wl1271_tx_work_locked(wl);
548 }
549
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200550 wl1271_rx(wl, wl->fw_status);
551 }
552
553 if (intr & WL1271_ACX_INTR_EVENT_A) {
554 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
555 wl1271_event_handle(wl, 0);
556 }
557
558 if (intr & WL1271_ACX_INTR_EVENT_B) {
559 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
560 wl1271_event_handle(wl, 1);
561 }
562
563 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
564 wl1271_debug(DEBUG_IRQ,
565 "WL1271_ACX_INTR_INIT_COMPLETE");
566
567 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
568 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
569
570 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300571 }
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
574 ieee80211_queue_work(wl->hw, &wl->irq_work);
575 else
576 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
577 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 wl1271_ps_elp_sleep(wl);
580
581out:
582 mutex_unlock(&wl->mutex);
583}
584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585static int wl1271_fetch_firmware(struct wl1271 *wl)
586{
587 const struct firmware *fw;
588 int ret;
589
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200590 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
592 if (ret < 0) {
593 wl1271_error("could not get firmware: %d", ret);
594 return ret;
595 }
596
597 if (fw->size % 4) {
598 wl1271_error("firmware size is not multiple of 32 bits: %zu",
599 fw->size);
600 ret = -EILSEQ;
601 goto out;
602 }
603
604 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300605 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606
607 if (!wl->fw) {
608 wl1271_error("could not allocate memory for the firmware");
609 ret = -ENOMEM;
610 goto out;
611 }
612
613 memcpy(wl->fw, fw->data, wl->fw_len);
614
615 ret = 0;
616
617out:
618 release_firmware(fw);
619
620 return ret;
621}
622
623static int wl1271_fetch_nvs(struct wl1271 *wl)
624{
625 const struct firmware *fw;
626 int ret;
627
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200628 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629
630 if (ret < 0) {
631 wl1271_error("could not get nvs file: %d", ret);
632 return ret;
633 }
634
Julia Lawall929ebd32010-05-15 23:16:39 +0200635 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 if (!wl->nvs) {
638 wl1271_error("could not allocate memory for the nvs file");
639 ret = -ENOMEM;
640 goto out;
641 }
642
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200643 wl->nvs_len = fw->size;
644
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645out:
646 release_firmware(fw);
647
648 return ret;
649}
650
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200651static void wl1271_recovery_work(struct work_struct *work)
652{
653 struct wl1271 *wl =
654 container_of(work, struct wl1271, recovery_work);
655
656 mutex_lock(&wl->mutex);
657
658 if (wl->state != WL1271_STATE_ON)
659 goto out;
660
661 wl1271_info("Hardware recovery in progress.");
662
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200663 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
664 ieee80211_connection_loss(wl->vif);
665
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200666 /* reboot the chipset */
667 __wl1271_op_remove_interface(wl);
668 ieee80211_restart_hw(wl->hw);
669
670out:
671 mutex_unlock(&wl->mutex);
672}
673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674static void wl1271_fw_wakeup(struct wl1271 *wl)
675{
676 u32 elp_reg;
677
678 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300679 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680}
681
682static int wl1271_setup(struct wl1271 *wl)
683{
684 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
685 if (!wl->fw_status)
686 return -ENOMEM;
687
688 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
689 if (!wl->tx_res_if) {
690 kfree(wl->fw_status);
691 return -ENOMEM;
692 }
693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 return 0;
695}
696
697static int wl1271_chip_wakeup(struct wl1271 *wl)
698{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300699 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 int ret = 0;
701
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200702 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200703 ret = wl1271_power_on(wl);
704 if (ret < 0)
705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200707 wl1271_io_reset(wl);
708 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
710 /* We don't need a real memory partition here, because we only want
711 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300712 memset(&partition, 0, sizeof(partition));
713 partition.reg.start = REGISTERS_BASE;
714 partition.reg.size = REGISTERS_DOWN_SIZE;
715 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716
717 /* ELP module wake up */
718 wl1271_fw_wakeup(wl);
719
720 /* whal_FwCtrl_BootSm() */
721
722 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200723 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724
725 /* 1. check if chip id is valid */
726
727 switch (wl->chip.id) {
728 case CHIP_ID_1271_PG10:
729 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
730 wl->chip.id);
731
732 ret = wl1271_setup(wl);
733 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 break;
736 case CHIP_ID_1271_PG20:
737 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
738 wl->chip.id);
739
740 ret = wl1271_setup(wl);
741 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 break;
744 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748 }
749
750 if (wl->fw == NULL) {
751 ret = wl1271_fetch_firmware(wl);
752 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200753 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 }
755
756 /* No NVS from netlink, try to get it from the filesystem */
757 if (wl->nvs == NULL) {
758 ret = wl1271_fetch_nvs(wl);
759 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200760 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761 }
762
763out:
764 return ret;
765}
766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767int wl1271_plt_start(struct wl1271 *wl)
768{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200769 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 int ret;
771
772 mutex_lock(&wl->mutex);
773
774 wl1271_notice("power up");
775
776 if (wl->state != WL1271_STATE_OFF) {
777 wl1271_error("cannot go into PLT state because not "
778 "in off state: %d", wl->state);
779 ret = -EBUSY;
780 goto out;
781 }
782
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200783 while (retries) {
784 retries--;
785 ret = wl1271_chip_wakeup(wl);
786 if (ret < 0)
787 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200789 ret = wl1271_boot(wl);
790 if (ret < 0)
791 goto power_off;
792
793 ret = wl1271_plt_init(wl);
794 if (ret < 0)
795 goto irq_disable;
796
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200797 wl->state = WL1271_STATE_PLT;
798 wl1271_notice("firmware booted in PLT mode (%s)",
799 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800 goto out;
801
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200802irq_disable:
803 wl1271_disable_interrupts(wl);
804 mutex_unlock(&wl->mutex);
805 /* Unlocking the mutex in the middle of handling is
806 inherently unsafe. In this case we deem it safe to do,
807 because we need to let any possibly pending IRQ out of
808 the system (and while we are WL1271_STATE_OFF the IRQ
809 work function will not do anything.) Also, any other
810 possible concurrent operations will fail due to the
811 current state, hence the wl1271 struct should be safe. */
812 cancel_work_sync(&wl->irq_work);
813 mutex_lock(&wl->mutex);
814power_off:
815 wl1271_power_off(wl);
816 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200818 wl1271_error("firmware boot in PLT mode failed despite %d retries",
819 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820out:
821 mutex_unlock(&wl->mutex);
822
823 return ret;
824}
825
826int wl1271_plt_stop(struct wl1271 *wl)
827{
828 int ret = 0;
829
830 mutex_lock(&wl->mutex);
831
832 wl1271_notice("power down");
833
834 if (wl->state != WL1271_STATE_PLT) {
835 wl1271_error("cannot power down because not in PLT "
836 "state: %d", wl->state);
837 ret = -EBUSY;
838 goto out;
839 }
840
841 wl1271_disable_interrupts(wl);
842 wl1271_power_off(wl);
843
844 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300845 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846
847out:
848 mutex_unlock(&wl->mutex);
849
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200850 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200851 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 return ret;
854}
855
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
857{
858 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200859 struct ieee80211_conf *conf = &hw->conf;
860 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
861 struct ieee80211_sta *sta = txinfo->control.sta;
862 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863
Shahar Levi18357852010-10-13 16:09:41 +0200864 /*
865 * peek into the rates configured in the STA entry.
866 * The rates set after connection stage, The first block only BG sets:
867 * the compare is for bit 0-16 of sta_rate_set. The second block add
868 * HT rates in case of HT supported.
869 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200870 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200871 if (sta &&
872 (sta->supp_rates[conf->channel->band] !=
873 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200874 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
875 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
876 }
Shahar Levi18357852010-10-13 16:09:41 +0200877
878#ifdef CONFIG_WL1271_HT
879 if (sta &&
880 sta->ht_cap.ht_supported &&
881 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
882 sta->ht_cap.mcs.rx_mask[0])) {
883 /* Clean MCS bits before setting them */
884 wl->sta_rate_set &= HW_BG_RATES_MASK;
885 wl->sta_rate_set |=
886 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
887 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
888 }
889#endif
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200890 spin_unlock_irqrestore(&wl->wl_lock, flags);
891
892 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 skb_queue_tail(&wl->tx_queue, skb);
894
895 /*
896 * The chip specific setup must run before the first TX packet -
897 * before that, the tx_work will not be initialized!
898 */
899
Ido Yariva5225502010-10-12 14:49:10 +0200900 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
901 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 /*
904 * The workqueue is slow to process the tx_queue and we need stop
905 * the queue here, otherwise the queue will get too long.
906 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200907 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
908 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200910 spin_lock_irqsave(&wl->wl_lock, flags);
911 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200912 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200913 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914 }
915
916 return NETDEV_TX_OK;
917}
918
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300919static struct notifier_block wl1271_dev_notifier = {
920 .notifier_call = wl1271_dev_notify,
921};
922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923static int wl1271_op_start(struct ieee80211_hw *hw)
924{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200925 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
926
927 /*
928 * We have to delay the booting of the hardware because
929 * we need to know the local MAC address before downloading and
930 * initializing the firmware. The MAC address cannot be changed
931 * after boot, and without the proper MAC address, the firmware
932 * will not function properly.
933 *
934 * The MAC address is first known when the corresponding interface
935 * is added. That is where we will initialize the hardware.
936 */
937
938 return 0;
939}
940
941static void wl1271_op_stop(struct ieee80211_hw *hw)
942{
943 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
944}
945
946static int wl1271_op_add_interface(struct ieee80211_hw *hw,
947 struct ieee80211_vif *vif)
948{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400950 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200951 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952 int ret = 0;
953
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200954 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
955 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
957 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200958 if (wl->vif) {
959 ret = -EBUSY;
960 goto out;
961 }
962
963 wl->vif = vif;
964
965 switch (vif->type) {
966 case NL80211_IFTYPE_STATION:
967 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200968 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200969 break;
970 case NL80211_IFTYPE_ADHOC:
971 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200972 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200973 break;
974 default:
975 ret = -EOPNOTSUPP;
976 goto out;
977 }
978
979 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980
981 if (wl->state != WL1271_STATE_OFF) {
982 wl1271_error("cannot start because not in off state: %d",
983 wl->state);
984 ret = -EBUSY;
985 goto out;
986 }
987
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988 while (retries) {
989 retries--;
990 ret = wl1271_chip_wakeup(wl);
991 if (ret < 0)
992 goto power_off;
993
994 ret = wl1271_boot(wl);
995 if (ret < 0)
996 goto power_off;
997
998 ret = wl1271_hw_init(wl);
999 if (ret < 0)
1000 goto irq_disable;
1001
1002 wl->state = WL1271_STATE_ON;
1003 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -04001004
1005 /* update hw/fw version info in wiphy struct */
1006 wiphy->hw_version = wl->chip.id;
1007 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1008 sizeof(wiphy->fw_version));
1009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 goto out;
1011
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001012irq_disable:
1013 wl1271_disable_interrupts(wl);
1014 mutex_unlock(&wl->mutex);
1015 /* Unlocking the mutex in the middle of handling is
1016 inherently unsafe. In this case we deem it safe to do,
1017 because we need to let any possibly pending IRQ out of
1018 the system (and while we are WL1271_STATE_OFF the IRQ
1019 work function will not do anything.) Also, any other
1020 possible concurrent operations will fail due to the
1021 current state, hence the wl1271 struct should be safe. */
1022 cancel_work_sync(&wl->irq_work);
1023 mutex_lock(&wl->mutex);
1024power_off:
1025 wl1271_power_off(wl);
1026 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001028 wl1271_error("firmware boot failed despite %d retries",
1029 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001030out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 mutex_unlock(&wl->mutex);
1032
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001033 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001034 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 return ret;
1037}
1038
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001039static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 int i;
1042
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001043 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001045 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001047 list_del(&wl->list);
1048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 WARN_ON(wl->state != WL1271_STATE_ON);
1050
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001051 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001052 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001053 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001054
Luciano Coelho08688d62010-07-08 17:50:07 +03001055 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001056 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1057 kfree(wl->scan.scanned_ch);
1058 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001059 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001060 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 }
1062
1063 wl->state = WL1271_STATE_OFF;
1064
1065 wl1271_disable_interrupts(wl);
1066
1067 mutex_unlock(&wl->mutex);
1068
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001069 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 cancel_work_sync(&wl->irq_work);
1071 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001072 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001073 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074
1075 mutex_lock(&wl->mutex);
1076
1077 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001078 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl1271_power_off(wl);
1080
1081 memset(wl->bssid, 0, ETH_ALEN);
1082 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1083 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001085 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001086 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
1088 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001089 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1091 wl->tx_blocks_available = 0;
1092 wl->tx_results_count = 0;
1093 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001094 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001095 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 wl->time_offset = 0;
1097 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001098 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1099 wl->sta_rate_set = 0;
1100 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001101 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001102 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 for (i = 0; i < NUM_TX_QUEUES; i++)
1105 wl->tx_blocks_freed[i] = 0;
1106
1107 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001108
1109 kfree(wl->fw_status);
1110 wl->fw_status = NULL;
1111 kfree(wl->tx_res_if);
1112 wl->tx_res_if = NULL;
1113 kfree(wl->target_mem_map);
1114 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001115}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001116
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001117static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1118 struct ieee80211_vif *vif)
1119{
1120 struct wl1271 *wl = hw->priv;
1121
1122 mutex_lock(&wl->mutex);
1123 WARN_ON(wl->vif != vif);
1124 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001126
1127 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128}
1129
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001130static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1131{
1132 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1133 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1134
1135 /* combine requested filters with current filter config */
1136 filters = wl->filters | filters;
1137
1138 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1139
1140 if (filters & FIF_PROMISC_IN_BSS) {
1141 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1142 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1143 wl->rx_config |= CFG_BSSID_FILTER_EN;
1144 }
1145 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1146 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1147 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1148 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1149 }
1150 if (filters & FIF_OTHER_BSS) {
1151 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1152 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1153 }
1154 if (filters & FIF_CONTROL) {
1155 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1156 wl->rx_filter |= CFG_RX_CTL_EN;
1157 }
1158 if (filters & FIF_FCSFAIL) {
1159 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1160 wl->rx_filter |= CFG_RX_FCS_ERROR;
1161 }
1162}
1163
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001164static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001165{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001166 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001167 /* we need to use a dummy BSSID for now */
1168 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1169 0xad, 0xbe, 0xef };
1170
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001171 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1172
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001173 /* pass through frames from all BSS */
1174 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1175
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001176 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001177 if (ret < 0)
1178 goto out;
1179
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001180 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001181
1182out:
1183 return ret;
1184}
1185
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001186static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001187{
1188 int ret;
1189
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001190 /*
1191 * One of the side effects of the JOIN command is that is clears
1192 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1193 * to a WPA/WPA2 access point will therefore kill the data-path.
1194 * Currently there is no supported scenario for JOIN during
1195 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1196 * must be handled somehow.
1197 *
1198 */
1199 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1200 wl1271_info("JOIN while associated.");
1201
1202 if (set_assoc)
1203 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1204
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001205 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1206 if (ret < 0)
1207 goto out;
1208
1209 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1210
1211 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1212 goto out;
1213
1214 /*
1215 * The join command disable the keep-alive mode, shut down its process,
1216 * and also clear the template config, so we need to reset it all after
1217 * the join. The acx_aid starts the keep-alive process, and the order
1218 * of the commands below is relevant.
1219 */
1220 ret = wl1271_acx_keep_alive_mode(wl, true);
1221 if (ret < 0)
1222 goto out;
1223
1224 ret = wl1271_acx_aid(wl, wl->aid);
1225 if (ret < 0)
1226 goto out;
1227
1228 ret = wl1271_cmd_build_klv_null_data(wl);
1229 if (ret < 0)
1230 goto out;
1231
1232 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1233 ACX_KEEP_ALIVE_TPL_VALID);
1234 if (ret < 0)
1235 goto out;
1236
1237out:
1238 return ret;
1239}
1240
1241static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001242{
1243 int ret;
1244
1245 /* to stop listening to a channel, we disconnect */
1246 ret = wl1271_cmd_disconnect(wl);
1247 if (ret < 0)
1248 goto out;
1249
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001250 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001251 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001252
1253 /* stop filterting packets based on bssid */
1254 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001255
1256out:
1257 return ret;
1258}
1259
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001260static void wl1271_set_band_rate(struct wl1271 *wl)
1261{
1262 if (wl->band == IEEE80211_BAND_2GHZ)
1263 wl->basic_rate_set = wl->conf.tx.basic_rate;
1264 else
1265 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1266}
1267
1268static u32 wl1271_min_rate_get(struct wl1271 *wl)
1269{
1270 int i;
1271 u32 rate = 0;
1272
1273 if (!wl->basic_rate_set) {
1274 WARN_ON(1);
1275 wl->basic_rate_set = wl->conf.tx.basic_rate;
1276 }
1277
1278 for (i = 0; !rate; i++) {
1279 if ((wl->basic_rate_set >> i) & 0x1)
1280 rate = 1 << i;
1281 }
1282
1283 return rate;
1284}
1285
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001286static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1287{
1288 int ret;
1289
1290 if (idle) {
1291 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1292 ret = wl1271_unjoin(wl);
1293 if (ret < 0)
1294 goto out;
1295 }
1296 wl->rate_set = wl1271_min_rate_get(wl);
1297 wl->sta_rate_set = 0;
1298 ret = wl1271_acx_rate_policies(wl);
1299 if (ret < 0)
1300 goto out;
1301 ret = wl1271_acx_keep_alive_config(
1302 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1303 ACX_KEEP_ALIVE_TPL_INVALID);
1304 if (ret < 0)
1305 goto out;
1306 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1307 } else {
1308 /* increment the session counter */
1309 wl->session_counter++;
1310 if (wl->session_counter >= SESSION_COUNTER_MAX)
1311 wl->session_counter = 0;
1312 ret = wl1271_dummy_join(wl);
1313 if (ret < 0)
1314 goto out;
1315 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1316 }
1317
1318out:
1319 return ret;
1320}
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1323{
1324 struct wl1271 *wl = hw->priv;
1325 struct ieee80211_conf *conf = &hw->conf;
1326 int channel, ret = 0;
1327
1328 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1329
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001330 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 channel,
1332 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001333 conf->power_level,
1334 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001336 /*
1337 * mac80211 will go to idle nearly immediately after transmitting some
1338 * frames, such as the deauth. To make sure those frames reach the air,
1339 * wait here until the TX queue is fully flushed.
1340 */
1341 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1342 (conf->flags & IEEE80211_CONF_IDLE))
1343 wl1271_tx_flush(wl);
1344
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 mutex_lock(&wl->mutex);
1346
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001347 if (unlikely(wl->state == WL1271_STATE_OFF))
1348 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 ret = wl1271_ps_elp_wakeup(wl, false);
1351 if (ret < 0)
1352 goto out;
1353
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001354 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001355 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1356 ((wl->band != conf->channel->band) ||
1357 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001358 wl->band = conf->channel->band;
1359 wl->channel = channel;
1360
1361 /*
1362 * FIXME: the mac80211 should really provide a fixed rate
1363 * to use here. for now, just use the smallest possible rate
1364 * for the band as a fixed rate for association frames and
1365 * other control messages.
1366 */
1367 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1368 wl1271_set_band_rate(wl);
1369
1370 wl->basic_rate = wl1271_min_rate_get(wl);
1371 ret = wl1271_acx_rate_policies(wl);
1372 if (ret < 0)
1373 wl1271_warning("rate policy for update channel "
1374 "failed %d", ret);
1375
1376 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001377 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001378 if (ret < 0)
1379 wl1271_warning("cmd join to update channel "
1380 "failed %d", ret);
1381 }
1382 }
1383
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001384 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001385 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1386 if (ret < 0)
1387 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388 }
1389
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001390 /*
1391 * if mac80211 changes the PSM mode, make sure the mode is not
1392 * incorrectly changed after the pspoll failure active window.
1393 */
1394 if (changed & IEEE80211_CONF_CHANGE_PS)
1395 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1396
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001397 if (conf->flags & IEEE80211_CONF_PS &&
1398 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1399 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
1401 /*
1402 * We enter PSM only if we're already associated.
1403 * If we're not, we'll enter it when joining an SSID,
1404 * through the bss_info_changed() hook.
1405 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001406 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001407 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001408 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001409 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001410 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001412 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001413 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001415 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001416
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001417 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001418 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001419 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 }
1421
1422 if (conf->power_level != wl->power_level) {
1423 ret = wl1271_acx_tx_power(wl, conf->power_level);
1424 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001425 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426
1427 wl->power_level = conf->power_level;
1428 }
1429
1430out_sleep:
1431 wl1271_ps_elp_sleep(wl);
1432
1433out:
1434 mutex_unlock(&wl->mutex);
1435
1436 return ret;
1437}
1438
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001439struct wl1271_filter_params {
1440 bool enabled;
1441 int mc_list_length;
1442 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1443};
1444
Jiri Pirko22bedad2010-04-01 21:22:57 +00001445static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1446 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001447{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001448 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001449 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001450 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001451
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001452 if (unlikely(wl->state == WL1271_STATE_OFF))
1453 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001454
Juuso Oikarinen74441132009-10-13 12:47:53 +03001455 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001456 if (!fp) {
1457 wl1271_error("Out of memory setting filters.");
1458 return 0;
1459 }
1460
1461 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001462 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001463 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1464 fp->enabled = false;
1465 } else {
1466 fp->enabled = true;
1467 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001468 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001469 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001470 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001471 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001472 }
1473
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001474 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001475}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001477#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1478 FIF_ALLMULTI | \
1479 FIF_FCSFAIL | \
1480 FIF_BCN_PRBRESP_PROMISC | \
1481 FIF_CONTROL | \
1482 FIF_OTHER_BSS)
1483
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1485 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001486 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001488 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001490 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
1492 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1493
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001494 mutex_lock(&wl->mutex);
1495
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001496 *total &= WL1271_SUPPORTED_FILTERS;
1497 changed &= WL1271_SUPPORTED_FILTERS;
1498
1499 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001500 goto out;
1501
1502 ret = wl1271_ps_elp_wakeup(wl, false);
1503 if (ret < 0)
1504 goto out;
1505
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001507 if (*total & FIF_ALLMULTI)
1508 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1509 else if (fp)
1510 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1511 fp->mc_list,
1512 fp->mc_list_length);
1513 if (ret < 0)
1514 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001516 /* determine, whether supported filter values have changed */
1517 if (changed == 0)
1518 goto out_sleep;
1519
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001520 /* configure filters */
1521 wl->filters = *total;
1522 wl1271_configure_filters(wl, 0);
1523
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001524 /* apply configured filters */
1525 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1526 if (ret < 0)
1527 goto out_sleep;
1528
1529out_sleep:
1530 wl1271_ps_elp_sleep(wl);
1531
1532out:
1533 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001534 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535}
1536
1537static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1538 struct ieee80211_vif *vif,
1539 struct ieee80211_sta *sta,
1540 struct ieee80211_key_conf *key_conf)
1541{
1542 struct wl1271 *wl = hw->priv;
1543 const u8 *addr;
1544 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001545 u32 tx_seq_32 = 0;
1546 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 u8 key_type;
1548
1549 static const u8 bcast_addr[ETH_ALEN] =
1550 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1551
1552 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1553
1554 addr = sta ? sta->addr : bcast_addr;
1555
1556 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1557 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1558 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001559 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560 key_conf->keylen, key_conf->flags);
1561 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1562
1563 if (is_zero_ether_addr(addr)) {
1564 /* We dont support TX only encryption */
1565 ret = -EOPNOTSUPP;
1566 goto out;
1567 }
1568
1569 mutex_lock(&wl->mutex);
1570
1571 ret = wl1271_ps_elp_wakeup(wl, false);
1572 if (ret < 0)
1573 goto out_unlock;
1574
Johannes Berg97359d12010-08-10 09:46:38 +02001575 switch (key_conf->cipher) {
1576 case WLAN_CIPHER_SUITE_WEP40:
1577 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 key_type = KEY_WEP;
1579
1580 key_conf->hw_key_idx = key_conf->keyidx;
1581 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001582 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 key_type = KEY_TKIP;
1584
1585 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001586 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1587 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001589 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 key_type = KEY_AES;
1591
1592 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001593 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1594 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001596 case WL1271_CIPHER_SUITE_GEM:
1597 key_type = KEY_GEM;
1598 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1599 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1600 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001602 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001603
1604 ret = -EOPNOTSUPP;
1605 goto out_sleep;
1606 }
1607
1608 switch (cmd) {
1609 case SET_KEY:
1610 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1611 key_conf->keyidx, key_type,
1612 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001613 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614 if (ret < 0) {
1615 wl1271_error("Could not add or replace key");
1616 goto out_sleep;
1617 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001618
1619 /* the default WEP key needs to be configured at least once */
1620 if (key_type == KEY_WEP) {
1621 ret = wl1271_cmd_set_default_wep_key(wl,
1622 wl->default_key);
1623 if (ret < 0)
1624 goto out_sleep;
1625 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001626 break;
1627
1628 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001629 /* The wl1271 does not allow to remove unicast keys - they
1630 will be cleared automatically on next CMD_JOIN. Ignore the
1631 request silently, as we dont want the mac80211 to emit
1632 an error message. */
1633 if (!is_broadcast_ether_addr(addr))
1634 break;
1635
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001636 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1637 key_conf->keyidx, key_type,
1638 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001639 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001640 if (ret < 0) {
1641 wl1271_error("Could not remove key");
1642 goto out_sleep;
1643 }
1644 break;
1645
1646 default:
1647 wl1271_error("Unsupported key cmd 0x%x", cmd);
1648 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649 break;
1650 }
1651
1652out_sleep:
1653 wl1271_ps_elp_sleep(wl);
1654
1655out_unlock:
1656 mutex_unlock(&wl->mutex);
1657
1658out:
1659 return ret;
1660}
1661
1662static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001663 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 struct cfg80211_scan_request *req)
1665{
1666 struct wl1271 *wl = hw->priv;
1667 int ret;
1668 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001669 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670
1671 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1672
1673 if (req->n_ssids) {
1674 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001675 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 }
1677
1678 mutex_lock(&wl->mutex);
1679
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001680 if (wl->state == WL1271_STATE_OFF) {
1681 /*
1682 * We cannot return -EBUSY here because cfg80211 will expect
1683 * a call to ieee80211_scan_completed if we do - in this case
1684 * there won't be any call.
1685 */
1686 ret = -EAGAIN;
1687 goto out;
1688 }
1689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690 ret = wl1271_ps_elp_wakeup(wl, false);
1691 if (ret < 0)
1692 goto out;
1693
Luciano Coelho5924f892010-08-04 03:46:22 +03001694 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695
1696 wl1271_ps_elp_sleep(wl);
1697
1698out:
1699 mutex_unlock(&wl->mutex);
1700
1701 return ret;
1702}
1703
1704static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1705{
1706 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001707 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708
1709 mutex_lock(&wl->mutex);
1710
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001711 if (unlikely(wl->state == WL1271_STATE_OFF))
1712 goto out;
1713
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 ret = wl1271_ps_elp_wakeup(wl, false);
1715 if (ret < 0)
1716 goto out;
1717
1718 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1719 if (ret < 0)
1720 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1721
1722 wl1271_ps_elp_sleep(wl);
1723
1724out:
1725 mutex_unlock(&wl->mutex);
1726
1727 return ret;
1728}
1729
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001730static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1731{
1732 u8 *ptr = beacon->data +
1733 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1734
1735 /* find the location of the ssid in the beacon */
1736 while (ptr < beacon->data + beacon->len) {
1737 if (ptr[0] == WLAN_EID_SSID) {
1738 wl->ssid_len = ptr[1];
1739 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1740 return;
1741 }
1742 ptr += ptr[1];
1743 }
1744 wl1271_error("ad-hoc beacon template has no SSID!\n");
1745}
1746
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1748 struct ieee80211_vif *vif,
1749 struct ieee80211_bss_conf *bss_conf,
1750 u32 changed)
1751{
1752 enum wl1271_cmd_ps_mode mode;
1753 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001754 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001755 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001756 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001757 int ret;
1758
1759 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1760
1761 mutex_lock(&wl->mutex);
1762
1763 ret = wl1271_ps_elp_wakeup(wl, false);
1764 if (ret < 0)
1765 goto out;
1766
Eliad Peller9ee82d52010-09-19 18:55:09 +02001767 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001768 (wl->bss_type == BSS_TYPE_IBSS)) {
1769 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1770 bss_conf->beacon_int);
1771
1772 wl->beacon_int = bss_conf->beacon_int;
1773 do_join = true;
1774 }
1775
Eliad Peller9ee82d52010-09-19 18:55:09 +02001776 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001777 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001778 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1779
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001780 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1781
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001782 if (beacon) {
1783 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001784
1785 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001786 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1787 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001788 beacon->len, 0,
1789 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001790
1791 if (ret < 0) {
1792 dev_kfree_skb(beacon);
1793 goto out_sleep;
1794 }
1795
1796 hdr = (struct ieee80211_hdr *) beacon->data;
1797 hdr->frame_control = cpu_to_le16(
1798 IEEE80211_FTYPE_MGMT |
1799 IEEE80211_STYPE_PROBE_RESP);
1800
1801 ret = wl1271_cmd_template_set(wl,
1802 CMD_TEMPL_PROBE_RESPONSE,
1803 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001804 beacon->len, 0,
1805 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001806 dev_kfree_skb(beacon);
1807 if (ret < 0)
1808 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001809
1810 /* Need to update the SSID (for filtering etc) */
1811 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001812 }
1813 }
1814
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001815 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1816 (wl->bss_type == BSS_TYPE_IBSS)) {
1817 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1818 bss_conf->enable_beacon ? "enabled" : "disabled");
1819
1820 if (bss_conf->enable_beacon)
1821 wl->set_bss_type = BSS_TYPE_IBSS;
1822 else
1823 wl->set_bss_type = BSS_TYPE_STA_BSS;
1824 do_join = true;
1825 }
1826
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001827 if (changed & BSS_CHANGED_CQM) {
1828 bool enable = false;
1829 if (bss_conf->cqm_rssi_thold)
1830 enable = true;
1831 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1832 bss_conf->cqm_rssi_thold,
1833 bss_conf->cqm_rssi_hyst);
1834 if (ret < 0)
1835 goto out;
1836 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1837 }
1838
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001839 if ((changed & BSS_CHANGED_BSSID) &&
1840 /*
1841 * Now we know the correct bssid, so we send a new join command
1842 * and enable the BSSID filter
1843 */
1844 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001845 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001846
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001847 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001848 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001849 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001850
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001851 ret = wl1271_build_qos_null_data(wl);
1852 if (ret < 0)
1853 goto out_sleep;
1854
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001855 /* filter out all packets not from this BSSID */
1856 wl1271_configure_filters(wl, 0);
1857
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001858 /* Need to update the BSSID (for filtering etc) */
1859 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001860 }
1861
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001862 if (changed & BSS_CHANGED_ASSOC) {
1863 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001864 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001866 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001867
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001868 wl->ps_poll_failures = 0;
1869
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001870 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001871 * use basic rates from AP, and determine lowest rate
1872 * to use with control frames.
1873 */
1874 rates = bss_conf->basic_rates;
1875 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1876 rates);
1877 wl->basic_rate = wl1271_min_rate_get(wl);
1878 ret = wl1271_acx_rate_policies(wl);
1879 if (ret < 0)
1880 goto out_sleep;
1881
1882 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001883 * with wl1271, we don't need to update the
1884 * beacon_int and dtim_period, because the firmware
1885 * updates it by itself when the first beacon is
1886 * received after a join.
1887 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1889 if (ret < 0)
1890 goto out_sleep;
1891
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001892 /*
1893 * The SSID is intentionally set to NULL here - the
1894 * firmware will set the probe request with a
1895 * broadcast SSID regardless of what we set in the
1896 * template.
1897 */
1898 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1899 NULL, 0, wl->band);
1900
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001901 /* enable the connection monitoring feature */
1902 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 if (ret < 0)
1904 goto out_sleep;
1905
1906 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001907 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1908 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001910 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001911 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03001912 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913 if (ret < 0)
1914 goto out_sleep;
1915 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001916 } else {
1917 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001918 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001919 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001920 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001921
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001922 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001923 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001924
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001925 /* revert back to minimum rates for the current band */
1926 wl1271_set_band_rate(wl);
1927 wl->basic_rate = wl1271_min_rate_get(wl);
1928 ret = wl1271_acx_rate_policies(wl);
1929 if (ret < 0)
1930 goto out_sleep;
1931
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001932 /* disable connection monitor features */
1933 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001934
1935 /* Disable the keep-alive feature */
1936 ret = wl1271_acx_keep_alive_mode(wl, false);
1937
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001938 if (ret < 0)
1939 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001941
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 if (changed & BSS_CHANGED_ERP_SLOT) {
1945 if (bss_conf->use_short_slot)
1946 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1947 else
1948 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1949 if (ret < 0) {
1950 wl1271_warning("Set slot time failed %d", ret);
1951 goto out_sleep;
1952 }
1953 }
1954
1955 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1956 if (bss_conf->use_short_preamble)
1957 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1958 else
1959 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1960 }
1961
1962 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1963 if (bss_conf->use_cts_prot)
1964 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1965 else
1966 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1967 if (ret < 0) {
1968 wl1271_warning("Set ctsprotect failed %d", ret);
1969 goto out_sleep;
1970 }
1971 }
1972
Shahar Levi18357852010-10-13 16:09:41 +02001973 /*
1974 * Takes care of: New association with HT enable,
1975 * HT information change in beacon.
1976 */
1977 if (sta &&
1978 (changed & BSS_CHANGED_HT) &&
1979 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
1980 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
1981 if (ret < 0) {
1982 wl1271_warning("Set ht cap true failed %d", ret);
1983 goto out_sleep;
1984 }
1985 ret = wl1271_acx_set_ht_information(wl,
1986 bss_conf->ht_operation_mode);
1987 if (ret < 0) {
1988 wl1271_warning("Set ht information failed %d", ret);
1989 goto out_sleep;
1990 }
1991 }
1992 /*
1993 * Takes care of: New association without HT,
1994 * Disassociation.
1995 */
1996 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
1997 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
1998 if (ret < 0) {
1999 wl1271_warning("Set ht cap false failed %d", ret);
2000 goto out_sleep;
2001 }
2002 }
2003
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002004 if (changed & BSS_CHANGED_ARP_FILTER) {
2005 __be32 addr = bss_conf->arp_addr_list[0];
2006 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2007
2008 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
2009 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
2010 else
2011 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
2012
2013 if (ret < 0)
2014 goto out_sleep;
2015 }
2016
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002017 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002018 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002019 if (ret < 0) {
2020 wl1271_warning("cmd join failed %d", ret);
2021 goto out_sleep;
2022 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002023 }
2024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025out_sleep:
2026 wl1271_ps_elp_sleep(wl);
2027
2028out:
2029 mutex_unlock(&wl->mutex);
2030}
2031
Kalle Valoc6999d82010-02-18 13:25:41 +02002032static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2033 const struct ieee80211_tx_queue_params *params)
2034{
2035 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002036 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002037 int ret;
2038
2039 mutex_lock(&wl->mutex);
2040
2041 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2042
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002043 ret = wl1271_ps_elp_wakeup(wl, false);
2044 if (ret < 0)
2045 goto out;
2046
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002047 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002048 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2049 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002050 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002051 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002052 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002053
Kalle Valo4695dc92010-03-18 12:26:38 +02002054 if (params->uapsd)
2055 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2056 else
2057 ps_scheme = CONF_PS_SCHEME_LEGACY;
2058
Kalle Valoc6999d82010-02-18 13:25:41 +02002059 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2060 CONF_CHANNEL_TYPE_EDCF,
2061 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002062 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002063 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002064 goto out_sleep;
2065
2066out_sleep:
2067 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002068
2069out:
2070 mutex_unlock(&wl->mutex);
2071
2072 return ret;
2073}
2074
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002075static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2076{
2077
2078 struct wl1271 *wl = hw->priv;
2079 u64 mactime = ULLONG_MAX;
2080 int ret;
2081
2082 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2083
2084 mutex_lock(&wl->mutex);
2085
2086 ret = wl1271_ps_elp_wakeup(wl, false);
2087 if (ret < 0)
2088 goto out;
2089
2090 ret = wl1271_acx_tsf_info(wl, &mactime);
2091 if (ret < 0)
2092 goto out_sleep;
2093
2094out_sleep:
2095 wl1271_ps_elp_sleep(wl);
2096
2097out:
2098 mutex_unlock(&wl->mutex);
2099 return mactime;
2100}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101
John W. Linvilleece550d2010-07-28 16:41:06 -04002102static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2103 struct survey_info *survey)
2104{
2105 struct wl1271 *wl = hw->priv;
2106 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002107
John W. Linvilleece550d2010-07-28 16:41:06 -04002108 if (idx != 0)
2109 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002110
John W. Linvilleece550d2010-07-28 16:41:06 -04002111 survey->channel = conf->channel;
2112 survey->filled = SURVEY_INFO_NOISE_DBM;
2113 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002114
John W. Linvilleece550d2010-07-28 16:41:06 -04002115 return 0;
2116}
2117
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002118/* can't be const, mac80211 writes to this */
2119static struct ieee80211_rate wl1271_rates[] = {
2120 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002121 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2122 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002123 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002124 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2125 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002126 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2127 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002128 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2129 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2131 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002132 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2133 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2135 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002136 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2137 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002139 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2140 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002142 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2143 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002145 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2146 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002147 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002148 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2149 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002151 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2152 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002154 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2155 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002157 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2158 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159};
2160
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002161/*
2162 * Can't be const, mac80211 writes to this. The order of the channels here
2163 * is designed to improve scanning.
2164 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002166 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002167 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002168 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002169 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002170 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2171 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2172 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2173 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2174 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2175 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2176 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2177 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2178 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179};
2180
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002181/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002182static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002183 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002184 7, /* CONF_HW_RXTX_RATE_MCS7 */
2185 6, /* CONF_HW_RXTX_RATE_MCS6 */
2186 5, /* CONF_HW_RXTX_RATE_MCS5 */
2187 4, /* CONF_HW_RXTX_RATE_MCS4 */
2188 3, /* CONF_HW_RXTX_RATE_MCS3 */
2189 2, /* CONF_HW_RXTX_RATE_MCS2 */
2190 1, /* CONF_HW_RXTX_RATE_MCS1 */
2191 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002192
2193 11, /* CONF_HW_RXTX_RATE_54 */
2194 10, /* CONF_HW_RXTX_RATE_48 */
2195 9, /* CONF_HW_RXTX_RATE_36 */
2196 8, /* CONF_HW_RXTX_RATE_24 */
2197
2198 /* TI-specific rate */
2199 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2200
2201 7, /* CONF_HW_RXTX_RATE_18 */
2202 6, /* CONF_HW_RXTX_RATE_12 */
2203 3, /* CONF_HW_RXTX_RATE_11 */
2204 5, /* CONF_HW_RXTX_RATE_9 */
2205 4, /* CONF_HW_RXTX_RATE_6 */
2206 2, /* CONF_HW_RXTX_RATE_5_5 */
2207 1, /* CONF_HW_RXTX_RATE_2 */
2208 0 /* CONF_HW_RXTX_RATE_1 */
2209};
2210
Shahar Levie8b03a22010-10-13 16:09:39 +02002211/* 11n STA capabilities */
2212#define HW_RX_HIGHEST_RATE 72
2213
Shahar Levi18357852010-10-13 16:09:41 +02002214#ifdef CONFIG_WL1271_HT
Shahar Levie8b03a22010-10-13 16:09:39 +02002215#define WL1271_HT_CAP { \
2216 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2217 .ht_supported = true, \
2218 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2219 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2220 .mcs = { \
2221 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2222 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2223 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2224 }, \
2225}
Shahar Levi18357852010-10-13 16:09:41 +02002226#else
2227#define WL1271_HT_CAP { \
2228 .ht_supported = false, \
2229}
2230#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002232/* can't be const, mac80211 writes to this */
2233static struct ieee80211_supported_band wl1271_band_2ghz = {
2234 .channels = wl1271_channels,
2235 .n_channels = ARRAY_SIZE(wl1271_channels),
2236 .bitrates = wl1271_rates,
2237 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi18357852010-10-13 16:09:41 +02002238 .ht_cap = WL1271_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239};
2240
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002241/* 5 GHz data rates for WL1273 */
2242static struct ieee80211_rate wl1271_rates_5ghz[] = {
2243 { .bitrate = 60,
2244 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2245 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2246 { .bitrate = 90,
2247 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2248 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2249 { .bitrate = 120,
2250 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2251 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2252 { .bitrate = 180,
2253 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2254 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2255 { .bitrate = 240,
2256 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2257 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2258 { .bitrate = 360,
2259 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2260 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2261 { .bitrate = 480,
2262 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2263 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2264 { .bitrate = 540,
2265 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2266 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2267};
2268
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002269/*
2270 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2271 * The order of the channels here is designed to improve scanning.
2272 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002273static struct ieee80211_channel wl1271_channels_5ghz[] = {
2274 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002275 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002276 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002277 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002278 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002279 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002280 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002281 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002282 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002283 { .hw_value = 184, .center_freq = 4920},
2284 { .hw_value = 189, .center_freq = 4945},
2285 { .hw_value = 9, .center_freq = 5045},
2286 { .hw_value = 36, .center_freq = 5180},
2287 { .hw_value = 46, .center_freq = 5230},
2288 { .hw_value = 64, .center_freq = 5320},
2289 { .hw_value = 116, .center_freq = 5580},
2290 { .hw_value = 136, .center_freq = 5680},
2291 { .hw_value = 192, .center_freq = 4960},
2292 { .hw_value = 11, .center_freq = 5055},
2293 { .hw_value = 38, .center_freq = 5190},
2294 { .hw_value = 48, .center_freq = 5240},
2295 { .hw_value = 100, .center_freq = 5500},
2296 { .hw_value = 120, .center_freq = 5600},
2297 { .hw_value = 140, .center_freq = 5700},
2298 { .hw_value = 185, .center_freq = 4925},
2299 { .hw_value = 196, .center_freq = 4980},
2300 { .hw_value = 12, .center_freq = 5060},
2301 { .hw_value = 40, .center_freq = 5200},
2302 { .hw_value = 52, .center_freq = 5260},
2303 { .hw_value = 104, .center_freq = 5520},
2304 { .hw_value = 124, .center_freq = 5620},
2305 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002306 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002307 { .hw_value = 187, .center_freq = 4935},
2308 { .hw_value = 7, .center_freq = 5035},
2309 { .hw_value = 16, .center_freq = 5080},
2310 { .hw_value = 42, .center_freq = 5210},
2311 { .hw_value = 56, .center_freq = 5280},
2312 { .hw_value = 108, .center_freq = 5540},
2313 { .hw_value = 128, .center_freq = 5640},
2314 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002315 { .hw_value = 165, .center_freq = 5825},
2316};
2317
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002318/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002319static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002320 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002321 7, /* CONF_HW_RXTX_RATE_MCS7 */
2322 6, /* CONF_HW_RXTX_RATE_MCS6 */
2323 5, /* CONF_HW_RXTX_RATE_MCS5 */
2324 4, /* CONF_HW_RXTX_RATE_MCS4 */
2325 3, /* CONF_HW_RXTX_RATE_MCS3 */
2326 2, /* CONF_HW_RXTX_RATE_MCS2 */
2327 1, /* CONF_HW_RXTX_RATE_MCS1 */
2328 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002329
2330 7, /* CONF_HW_RXTX_RATE_54 */
2331 6, /* CONF_HW_RXTX_RATE_48 */
2332 5, /* CONF_HW_RXTX_RATE_36 */
2333 4, /* CONF_HW_RXTX_RATE_24 */
2334
2335 /* TI-specific rate */
2336 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2337
2338 3, /* CONF_HW_RXTX_RATE_18 */
2339 2, /* CONF_HW_RXTX_RATE_12 */
2340 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2341 1, /* CONF_HW_RXTX_RATE_9 */
2342 0, /* CONF_HW_RXTX_RATE_6 */
2343 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2344 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2345 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2346};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002347
2348static struct ieee80211_supported_band wl1271_band_5ghz = {
2349 .channels = wl1271_channels_5ghz,
2350 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2351 .bitrates = wl1271_rates_5ghz,
2352 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi18357852010-10-13 16:09:41 +02002353 .ht_cap = WL1271_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002354};
2355
Tobias Klausera0ea9492010-05-20 10:38:11 +02002356static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002357 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2358 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2359};
2360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361static const struct ieee80211_ops wl1271_ops = {
2362 .start = wl1271_op_start,
2363 .stop = wl1271_op_stop,
2364 .add_interface = wl1271_op_add_interface,
2365 .remove_interface = wl1271_op_remove_interface,
2366 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002367 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 .configure_filter = wl1271_op_configure_filter,
2369 .tx = wl1271_op_tx,
2370 .set_key = wl1271_op_set_key,
2371 .hw_scan = wl1271_op_hw_scan,
2372 .bss_info_changed = wl1271_op_bss_info_changed,
2373 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002374 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002375 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002376 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002377 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378};
2379
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002380
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002381u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002382{
2383 u8 idx;
2384
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002385 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002386
2387 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2388 wl1271_error("Illegal RX rate from HW: %d", rate);
2389 return 0;
2390 }
2391
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002392 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002393 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2394 wl1271_error("Unsupported RX rate from HW: %d", rate);
2395 return 0;
2396 }
2397
2398 return idx;
2399}
2400
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002401static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2402 struct device_attribute *attr,
2403 char *buf)
2404{
2405 struct wl1271 *wl = dev_get_drvdata(dev);
2406 ssize_t len;
2407
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002408 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002409
2410 mutex_lock(&wl->mutex);
2411 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2412 wl->sg_enabled);
2413 mutex_unlock(&wl->mutex);
2414
2415 return len;
2416
2417}
2418
2419static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2420 struct device_attribute *attr,
2421 const char *buf, size_t count)
2422{
2423 struct wl1271 *wl = dev_get_drvdata(dev);
2424 unsigned long res;
2425 int ret;
2426
2427 ret = strict_strtoul(buf, 10, &res);
2428
2429 if (ret < 0) {
2430 wl1271_warning("incorrect value written to bt_coex_mode");
2431 return count;
2432 }
2433
2434 mutex_lock(&wl->mutex);
2435
2436 res = !!res;
2437
2438 if (res == wl->sg_enabled)
2439 goto out;
2440
2441 wl->sg_enabled = res;
2442
2443 if (wl->state == WL1271_STATE_OFF)
2444 goto out;
2445
2446 ret = wl1271_ps_elp_wakeup(wl, false);
2447 if (ret < 0)
2448 goto out;
2449
2450 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2451 wl1271_ps_elp_sleep(wl);
2452
2453 out:
2454 mutex_unlock(&wl->mutex);
2455 return count;
2456}
2457
2458static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2459 wl1271_sysfs_show_bt_coex_state,
2460 wl1271_sysfs_store_bt_coex_state);
2461
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002462static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2463 struct device_attribute *attr,
2464 char *buf)
2465{
2466 struct wl1271 *wl = dev_get_drvdata(dev);
2467 ssize_t len;
2468
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002469 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002470
2471 mutex_lock(&wl->mutex);
2472 if (wl->hw_pg_ver >= 0)
2473 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2474 else
2475 len = snprintf(buf, len, "n/a\n");
2476 mutex_unlock(&wl->mutex);
2477
2478 return len;
2479}
2480
2481static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2482 wl1271_sysfs_show_hw_pg_ver, NULL);
2483
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002484int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485{
2486 int ret;
2487
2488 if (wl->mac80211_registered)
2489 return 0;
2490
2491 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2492
2493 ret = ieee80211_register_hw(wl->hw);
2494 if (ret < 0) {
2495 wl1271_error("unable to register mac80211 hw: %d", ret);
2496 return ret;
2497 }
2498
2499 wl->mac80211_registered = true;
2500
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002501 register_netdevice_notifier(&wl1271_dev_notifier);
2502
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002503 wl1271_notice("loaded");
2504
2505 return 0;
2506}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002507EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002509void wl1271_unregister_hw(struct wl1271 *wl)
2510{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002511 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002512 ieee80211_unregister_hw(wl->hw);
2513 wl->mac80211_registered = false;
2514
2515}
2516EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2517
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002518int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002520 static const u32 cipher_suites[] = {
2521 WLAN_CIPHER_SUITE_WEP40,
2522 WLAN_CIPHER_SUITE_WEP104,
2523 WLAN_CIPHER_SUITE_TKIP,
2524 WLAN_CIPHER_SUITE_CCMP,
2525 WL1271_CIPHER_SUITE_GEM,
2526 };
2527
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002528 /* The tx descriptor buffer and the TKIP space. */
2529 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2530 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
2532 /* unit us */
2533 /* FIXME: find a proper value */
2534 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002535 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002536
2537 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002538 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002539 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002540 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002541 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002542 IEEE80211_HW_CONNECTION_MONITOR |
2543 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002545 wl->hw->wiphy->cipher_suites = cipher_suites;
2546 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2547
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002548 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2549 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550 wl->hw->wiphy->max_scan_ssids = 1;
2551 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002552 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002553
Kalle Valo12bd8942010-03-18 12:26:33 +02002554 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002555 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002556
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002557 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002558
2559 return 0;
2560}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002561EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002562
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002564
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002565struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002568 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002570 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002571 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572
2573 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2574 if (!hw) {
2575 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002576 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002577 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578 }
2579
Julia Lawall929ebd32010-05-15 23:16:39 +02002580 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002581 if (!plat_dev) {
2582 wl1271_error("could not allocate platform_device");
2583 ret = -ENOMEM;
2584 goto err_plat_alloc;
2585 }
2586
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 wl = hw->priv;
2588 memset(wl, 0, sizeof(*wl));
2589
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002590 INIT_LIST_HEAD(&wl->list);
2591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002593 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594
2595 skb_queue_head_init(&wl->tx_queue);
2596
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002597 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002598 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002599 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2600 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2601 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2602 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002603 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002604 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002606 wl->rx_counter = 0;
2607 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2608 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002609 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002610 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002611 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002612 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002613 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2614 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002615 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002616 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002617 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002618 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002619 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002620
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002621 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002622 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623 wl->tx_frames[i] = NULL;
2624
2625 spin_lock_init(&wl->wl_lock);
2626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627 wl->state = WL1271_STATE_OFF;
2628 mutex_init(&wl->mutex);
2629
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002630 /* Apply default driver configuration. */
2631 wl1271_conf_init(wl);
2632
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002633 wl1271_debugfs_init(wl);
2634
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002635 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2636 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2637 if (!wl->aggr_buf) {
2638 ret = -ENOMEM;
2639 goto err_hw;
2640 }
2641
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002642 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002643 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002644 if (ret) {
2645 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002646 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002647 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002648 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002649
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002650 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002651 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002652 if (ret < 0) {
2653 wl1271_error("failed to create sysfs file bt_coex_state");
2654 goto err_platform;
2655 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002656
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002657 /* Create sysfs file to get HW PG version */
2658 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2659 if (ret < 0) {
2660 wl1271_error("failed to create sysfs file hw_pg_ver");
2661 goto err_bt_coex_state;
2662 }
2663
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002664 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002665
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002666err_bt_coex_state:
2667 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2668
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002669err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002670 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002671
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002672err_aggr:
2673 free_pages((unsigned long)wl->aggr_buf, order);
2674
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002675err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002676 wl1271_debugfs_exit(wl);
2677 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002678
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002679err_plat_alloc:
2680 ieee80211_free_hw(hw);
2681
2682err_hw_alloc:
2683
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002684 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002685}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002686EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002687
2688int wl1271_free_hw(struct wl1271 *wl)
2689{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002690 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002691 free_pages((unsigned long)wl->aggr_buf,
2692 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002693 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002694
2695 wl1271_debugfs_exit(wl);
2696
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002697 vfree(wl->fw);
2698 wl->fw = NULL;
2699 kfree(wl->nvs);
2700 wl->nvs = NULL;
2701
2702 kfree(wl->fw_status);
2703 kfree(wl->tx_res_if);
2704
2705 ieee80211_free_hw(wl->hw);
2706
2707 return 0;
2708}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002709EXPORT_SYMBOL_GPL(wl1271_free_hw);
2710
2711MODULE_LICENSE("GPL");
2712MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2713MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");