blob: a3a1ebc578a3699d8f718b8d3878481d128342c5 [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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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;
Eliad Peller71125ab2010-10-28 21:46:43 +0200953 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200955 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
956 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957
958 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200959 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +0200960 wl1271_debug(DEBUG_MAC80211,
961 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200962 ret = -EBUSY;
963 goto out;
964 }
965
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200966 switch (vif->type) {
967 case NL80211_IFTYPE_STATION:
968 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200969 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200970 break;
971 case NL80211_IFTYPE_ADHOC:
972 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200973 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200974 break;
975 default:
976 ret = -EOPNOTSUPP;
977 goto out;
978 }
979
980 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981
982 if (wl->state != WL1271_STATE_OFF) {
983 wl1271_error("cannot start because not in off state: %d",
984 wl->state);
985 ret = -EBUSY;
986 goto out;
987 }
988
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200989 while (retries) {
990 retries--;
991 ret = wl1271_chip_wakeup(wl);
992 if (ret < 0)
993 goto power_off;
994
995 ret = wl1271_boot(wl);
996 if (ret < 0)
997 goto power_off;
998
999 ret = wl1271_hw_init(wl);
1000 if (ret < 0)
1001 goto irq_disable;
1002
Eliad Peller71125ab2010-10-28 21:46:43 +02001003 booted = true;
1004 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001006irq_disable:
1007 wl1271_disable_interrupts(wl);
1008 mutex_unlock(&wl->mutex);
1009 /* Unlocking the mutex in the middle of handling is
1010 inherently unsafe. In this case we deem it safe to do,
1011 because we need to let any possibly pending IRQ out of
1012 the system (and while we are WL1271_STATE_OFF the IRQ
1013 work function will not do anything.) Also, any other
1014 possible concurrent operations will fail due to the
1015 current state, hence the wl1271 struct should be safe. */
1016 cancel_work_sync(&wl->irq_work);
1017 mutex_lock(&wl->mutex);
1018power_off:
1019 wl1271_power_off(wl);
1020 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021
Eliad Peller71125ab2010-10-28 21:46:43 +02001022 if (!booted) {
1023 wl1271_error("firmware boot failed despite %d retries",
1024 WL1271_BOOT_RETRIES);
1025 goto out;
1026 }
1027
1028 wl->vif = vif;
1029 wl->state = WL1271_STATE_ON;
1030 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1031
1032 /* update hw/fw version info in wiphy struct */
1033 wiphy->hw_version = wl->chip.id;
1034 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1035 sizeof(wiphy->fw_version));
1036
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001037out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 mutex_unlock(&wl->mutex);
1039
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001040 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001041 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001042
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 return ret;
1044}
1045
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001046static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 int i;
1049
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001050 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001052 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001054 list_del(&wl->list);
1055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056 WARN_ON(wl->state != WL1271_STATE_ON);
1057
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001058 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001059 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001060 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001061
Luciano Coelho08688d62010-07-08 17:50:07 +03001062 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001063 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1064 kfree(wl->scan.scanned_ch);
1065 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001066 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001067 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 }
1069
1070 wl->state = WL1271_STATE_OFF;
1071
1072 wl1271_disable_interrupts(wl);
1073
1074 mutex_unlock(&wl->mutex);
1075
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001076 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 cancel_work_sync(&wl->irq_work);
1078 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001079 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001080 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
1082 mutex_lock(&wl->mutex);
1083
1084 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c42010-05-24 11:18:17 +03001085 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 wl1271_power_off(wl);
1087
1088 memset(wl->bssid, 0, ETH_ALEN);
1089 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1090 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001092 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001093 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001096 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1098 wl->tx_blocks_available = 0;
1099 wl->tx_results_count = 0;
1100 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001101 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001102 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103 wl->time_offset = 0;
1104 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001105 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1106 wl->sta_rate_set = 0;
1107 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001108 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001109 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 for (i = 0; i < NUM_TX_QUEUES; i++)
1112 wl->tx_blocks_freed[i] = 0;
1113
1114 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001115
1116 kfree(wl->fw_status);
1117 wl->fw_status = NULL;
1118 kfree(wl->tx_res_if);
1119 wl->tx_res_if = NULL;
1120 kfree(wl->target_mem_map);
1121 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001122}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001123
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001124static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1125 struct ieee80211_vif *vif)
1126{
1127 struct wl1271 *wl = hw->priv;
1128
1129 mutex_lock(&wl->mutex);
1130 WARN_ON(wl->vif != vif);
1131 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001133
1134 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135}
1136
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001137static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1138{
1139 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1140 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1141
1142 /* combine requested filters with current filter config */
1143 filters = wl->filters | filters;
1144
1145 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1146
1147 if (filters & FIF_PROMISC_IN_BSS) {
1148 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1149 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1150 wl->rx_config |= CFG_BSSID_FILTER_EN;
1151 }
1152 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1153 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1154 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1155 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1156 }
1157 if (filters & FIF_OTHER_BSS) {
1158 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1159 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1160 }
1161 if (filters & FIF_CONTROL) {
1162 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1163 wl->rx_filter |= CFG_RX_CTL_EN;
1164 }
1165 if (filters & FIF_FCSFAIL) {
1166 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1167 wl->rx_filter |= CFG_RX_FCS_ERROR;
1168 }
1169}
1170
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001171static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001172{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001173 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001174 /* we need to use a dummy BSSID for now */
1175 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1176 0xad, 0xbe, 0xef };
1177
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001178 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1179
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001180 /* pass through frames from all BSS */
1181 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1182
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001183 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001184 if (ret < 0)
1185 goto out;
1186
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001187 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001188
1189out:
1190 return ret;
1191}
1192
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001193static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001194{
1195 int ret;
1196
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001197 /*
1198 * One of the side effects of the JOIN command is that is clears
1199 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1200 * to a WPA/WPA2 access point will therefore kill the data-path.
1201 * Currently there is no supported scenario for JOIN during
1202 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1203 * must be handled somehow.
1204 *
1205 */
1206 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1207 wl1271_info("JOIN while associated.");
1208
1209 if (set_assoc)
1210 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1211
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001212 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1213 if (ret < 0)
1214 goto out;
1215
1216 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1217
1218 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1219 goto out;
1220
1221 /*
1222 * The join command disable the keep-alive mode, shut down its process,
1223 * and also clear the template config, so we need to reset it all after
1224 * the join. The acx_aid starts the keep-alive process, and the order
1225 * of the commands below is relevant.
1226 */
1227 ret = wl1271_acx_keep_alive_mode(wl, true);
1228 if (ret < 0)
1229 goto out;
1230
1231 ret = wl1271_acx_aid(wl, wl->aid);
1232 if (ret < 0)
1233 goto out;
1234
1235 ret = wl1271_cmd_build_klv_null_data(wl);
1236 if (ret < 0)
1237 goto out;
1238
1239 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1240 ACX_KEEP_ALIVE_TPL_VALID);
1241 if (ret < 0)
1242 goto out;
1243
1244out:
1245 return ret;
1246}
1247
1248static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001249{
1250 int ret;
1251
1252 /* to stop listening to a channel, we disconnect */
1253 ret = wl1271_cmd_disconnect(wl);
1254 if (ret < 0)
1255 goto out;
1256
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001257 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001258 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001259
1260 /* stop filterting packets based on bssid */
1261 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001262
1263out:
1264 return ret;
1265}
1266
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001267static void wl1271_set_band_rate(struct wl1271 *wl)
1268{
1269 if (wl->band == IEEE80211_BAND_2GHZ)
1270 wl->basic_rate_set = wl->conf.tx.basic_rate;
1271 else
1272 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1273}
1274
1275static u32 wl1271_min_rate_get(struct wl1271 *wl)
1276{
1277 int i;
1278 u32 rate = 0;
1279
1280 if (!wl->basic_rate_set) {
1281 WARN_ON(1);
1282 wl->basic_rate_set = wl->conf.tx.basic_rate;
1283 }
1284
1285 for (i = 0; !rate; i++) {
1286 if ((wl->basic_rate_set >> i) & 0x1)
1287 rate = 1 << i;
1288 }
1289
1290 return rate;
1291}
1292
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001293static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1294{
1295 int ret;
1296
1297 if (idle) {
1298 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1299 ret = wl1271_unjoin(wl);
1300 if (ret < 0)
1301 goto out;
1302 }
1303 wl->rate_set = wl1271_min_rate_get(wl);
1304 wl->sta_rate_set = 0;
1305 ret = wl1271_acx_rate_policies(wl);
1306 if (ret < 0)
1307 goto out;
1308 ret = wl1271_acx_keep_alive_config(
1309 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1310 ACX_KEEP_ALIVE_TPL_INVALID);
1311 if (ret < 0)
1312 goto out;
1313 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1314 } else {
1315 /* increment the session counter */
1316 wl->session_counter++;
1317 if (wl->session_counter >= SESSION_COUNTER_MAX)
1318 wl->session_counter = 0;
1319 ret = wl1271_dummy_join(wl);
1320 if (ret < 0)
1321 goto out;
1322 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1323 }
1324
1325out:
1326 return ret;
1327}
1328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1330{
1331 struct wl1271 *wl = hw->priv;
1332 struct ieee80211_conf *conf = &hw->conf;
1333 int channel, ret = 0;
1334
1335 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1336
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001337 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 channel,
1339 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001340 conf->power_level,
1341 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342
Juuso Oikarinen781608c42010-05-24 11:18:17 +03001343 /*
1344 * mac80211 will go to idle nearly immediately after transmitting some
1345 * frames, such as the deauth. To make sure those frames reach the air,
1346 * wait here until the TX queue is fully flushed.
1347 */
1348 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1349 (conf->flags & IEEE80211_CONF_IDLE))
1350 wl1271_tx_flush(wl);
1351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 mutex_lock(&wl->mutex);
1353
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001354 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1355 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001356 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001357 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 ret = wl1271_ps_elp_wakeup(wl, false);
1360 if (ret < 0)
1361 goto out;
1362
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001363 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001364 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1365 ((wl->band != conf->channel->band) ||
1366 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001367 wl->band = conf->channel->band;
1368 wl->channel = channel;
1369
1370 /*
1371 * FIXME: the mac80211 should really provide a fixed rate
1372 * to use here. for now, just use the smallest possible rate
1373 * for the band as a fixed rate for association frames and
1374 * other control messages.
1375 */
1376 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1377 wl1271_set_band_rate(wl);
1378
1379 wl->basic_rate = wl1271_min_rate_get(wl);
1380 ret = wl1271_acx_rate_policies(wl);
1381 if (ret < 0)
1382 wl1271_warning("rate policy for update channel "
1383 "failed %d", ret);
1384
1385 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001386 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001387 if (ret < 0)
1388 wl1271_warning("cmd join to update channel "
1389 "failed %d", ret);
1390 }
1391 }
1392
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001393 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001394 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1395 if (ret < 0)
1396 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397 }
1398
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001399 /*
1400 * if mac80211 changes the PSM mode, make sure the mode is not
1401 * incorrectly changed after the pspoll failure active window.
1402 */
1403 if (changed & IEEE80211_CONF_CHANGE_PS)
1404 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1405
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001406 if (conf->flags & IEEE80211_CONF_PS &&
1407 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1408 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409
1410 /*
1411 * We enter PSM only if we're already associated.
1412 * If we're not, we'll enter it when joining an SSID,
1413 * through the bss_info_changed() hook.
1414 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001415 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001416 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001417 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001418 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001419 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001421 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001422 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001424 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001426 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001427 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001428 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 }
1430
1431 if (conf->power_level != wl->power_level) {
1432 ret = wl1271_acx_tx_power(wl, conf->power_level);
1433 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001434 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435
1436 wl->power_level = conf->power_level;
1437 }
1438
1439out_sleep:
1440 wl1271_ps_elp_sleep(wl);
1441
1442out:
1443 mutex_unlock(&wl->mutex);
1444
1445 return ret;
1446}
1447
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001448struct wl1271_filter_params {
1449 bool enabled;
1450 int mc_list_length;
1451 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1452};
1453
Jiri Pirko22bedad32010-04-01 21:22:57 +00001454static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1455 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001456{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001457 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001458 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001459 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001460
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001461 if (unlikely(wl->state == WL1271_STATE_OFF))
1462 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001463
Juuso Oikarinen74441132009-10-13 12:47:53 +03001464 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001465 if (!fp) {
1466 wl1271_error("Out of memory setting filters.");
1467 return 0;
1468 }
1469
1470 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001471 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001472 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1473 fp->enabled = false;
1474 } else {
1475 fp->enabled = true;
1476 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001477 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001478 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001479 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001480 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001481 }
1482
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001483 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001484}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001486#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1487 FIF_ALLMULTI | \
1488 FIF_FCSFAIL | \
1489 FIF_BCN_PRBRESP_PROMISC | \
1490 FIF_CONTROL | \
1491 FIF_OTHER_BSS)
1492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1494 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001495 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001497 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001499 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500
1501 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1502
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001503 mutex_lock(&wl->mutex);
1504
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001505 *total &= WL1271_SUPPORTED_FILTERS;
1506 changed &= WL1271_SUPPORTED_FILTERS;
1507
1508 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001509 goto out;
1510
1511 ret = wl1271_ps_elp_wakeup(wl, false);
1512 if (ret < 0)
1513 goto out;
1514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001516 if (*total & FIF_ALLMULTI)
1517 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1518 else if (fp)
1519 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1520 fp->mc_list,
1521 fp->mc_list_length);
1522 if (ret < 0)
1523 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001525 /* determine, whether supported filter values have changed */
1526 if (changed == 0)
1527 goto out_sleep;
1528
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001529 /* configure filters */
1530 wl->filters = *total;
1531 wl1271_configure_filters(wl, 0);
1532
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001533 /* apply configured filters */
1534 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1535 if (ret < 0)
1536 goto out_sleep;
1537
1538out_sleep:
1539 wl1271_ps_elp_sleep(wl);
1540
1541out:
1542 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001543 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544}
1545
1546static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1547 struct ieee80211_vif *vif,
1548 struct ieee80211_sta *sta,
1549 struct ieee80211_key_conf *key_conf)
1550{
1551 struct wl1271 *wl = hw->priv;
1552 const u8 *addr;
1553 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001554 u32 tx_seq_32 = 0;
1555 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556 u8 key_type;
1557
1558 static const u8 bcast_addr[ETH_ALEN] =
1559 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1560
1561 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1562
1563 addr = sta ? sta->addr : bcast_addr;
1564
1565 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1566 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1567 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001568 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 key_conf->keylen, key_conf->flags);
1570 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1571
1572 if (is_zero_ether_addr(addr)) {
1573 /* We dont support TX only encryption */
1574 ret = -EOPNOTSUPP;
1575 goto out;
1576 }
1577
1578 mutex_lock(&wl->mutex);
1579
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001580 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1581 ret = -EAGAIN;
1582 goto out_unlock;
1583 }
1584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 ret = wl1271_ps_elp_wakeup(wl, false);
1586 if (ret < 0)
1587 goto out_unlock;
1588
Johannes Berg97359d12010-08-10 09:46:38 +02001589 switch (key_conf->cipher) {
1590 case WLAN_CIPHER_SUITE_WEP40:
1591 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 key_type = KEY_WEP;
1593
1594 key_conf->hw_key_idx = key_conf->keyidx;
1595 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001596 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597 key_type = KEY_TKIP;
1598
1599 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001600 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1601 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001603 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604 key_type = KEY_AES;
1605
1606 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001607 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1608 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001610 case WL1271_CIPHER_SUITE_GEM:
1611 key_type = KEY_GEM;
1612 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1613 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1614 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001616 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001617
1618 ret = -EOPNOTSUPP;
1619 goto out_sleep;
1620 }
1621
1622 switch (cmd) {
1623 case SET_KEY:
1624 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1625 key_conf->keyidx, key_type,
1626 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001627 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628 if (ret < 0) {
1629 wl1271_error("Could not add or replace key");
1630 goto out_sleep;
1631 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001632
1633 /* the default WEP key needs to be configured at least once */
1634 if (key_type == KEY_WEP) {
1635 ret = wl1271_cmd_set_default_wep_key(wl,
1636 wl->default_key);
1637 if (ret < 0)
1638 goto out_sleep;
1639 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001640 break;
1641
1642 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001643 /* The wl1271 does not allow to remove unicast keys - they
1644 will be cleared automatically on next CMD_JOIN. Ignore the
1645 request silently, as we dont want the mac80211 to emit
1646 an error message. */
1647 if (!is_broadcast_ether_addr(addr))
1648 break;
1649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1651 key_conf->keyidx, key_type,
1652 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001653 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 if (ret < 0) {
1655 wl1271_error("Could not remove key");
1656 goto out_sleep;
1657 }
1658 break;
1659
1660 default:
1661 wl1271_error("Unsupported key cmd 0x%x", cmd);
1662 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663 break;
1664 }
1665
1666out_sleep:
1667 wl1271_ps_elp_sleep(wl);
1668
1669out_unlock:
1670 mutex_unlock(&wl->mutex);
1671
1672out:
1673 return ret;
1674}
1675
1676static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001677 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001678 struct cfg80211_scan_request *req)
1679{
1680 struct wl1271 *wl = hw->priv;
1681 int ret;
1682 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001683 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684
1685 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1686
1687 if (req->n_ssids) {
1688 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001689 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690 }
1691
1692 mutex_lock(&wl->mutex);
1693
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001694 if (wl->state == WL1271_STATE_OFF) {
1695 /*
1696 * We cannot return -EBUSY here because cfg80211 will expect
1697 * a call to ieee80211_scan_completed if we do - in this case
1698 * there won't be any call.
1699 */
1700 ret = -EAGAIN;
1701 goto out;
1702 }
1703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704 ret = wl1271_ps_elp_wakeup(wl, false);
1705 if (ret < 0)
1706 goto out;
1707
Luciano Coelho5924f892010-08-04 03:46:22 +03001708 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709
1710 wl1271_ps_elp_sleep(wl);
1711
1712out:
1713 mutex_unlock(&wl->mutex);
1714
1715 return ret;
1716}
1717
1718static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1719{
1720 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001721 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722
1723 mutex_lock(&wl->mutex);
1724
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001725 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1726 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001727 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001728 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001729
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001730 ret = wl1271_ps_elp_wakeup(wl, false);
1731 if (ret < 0)
1732 goto out;
1733
1734 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1735 if (ret < 0)
1736 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1737
1738 wl1271_ps_elp_sleep(wl);
1739
1740out:
1741 mutex_unlock(&wl->mutex);
1742
1743 return ret;
1744}
1745
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001746static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1747{
1748 u8 *ptr = beacon->data +
1749 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1750
1751 /* find the location of the ssid in the beacon */
1752 while (ptr < beacon->data + beacon->len) {
1753 if (ptr[0] == WLAN_EID_SSID) {
1754 wl->ssid_len = ptr[1];
1755 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1756 return;
1757 }
1758 ptr += ptr[1];
1759 }
1760 wl1271_error("ad-hoc beacon template has no SSID!\n");
1761}
1762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001763static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1764 struct ieee80211_vif *vif,
1765 struct ieee80211_bss_conf *bss_conf,
1766 u32 changed)
1767{
1768 enum wl1271_cmd_ps_mode mode;
1769 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001770 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001771 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001772 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773 int ret;
1774
1775 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1776
1777 mutex_lock(&wl->mutex);
1778
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001779 if (unlikely(wl->state == WL1271_STATE_OFF))
1780 goto out;
1781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782 ret = wl1271_ps_elp_wakeup(wl, false);
1783 if (ret < 0)
1784 goto out;
1785
Eliad Peller9ee82d52010-09-19 18:55:09 +02001786 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001787 (wl->bss_type == BSS_TYPE_IBSS)) {
1788 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1789 bss_conf->beacon_int);
1790
1791 wl->beacon_int = bss_conf->beacon_int;
1792 do_join = true;
1793 }
1794
Eliad Peller9ee82d52010-09-19 18:55:09 +02001795 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001796 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001797 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1798
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001799 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1800
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001801 if (beacon) {
1802 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001803
1804 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001805 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1806 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001807 beacon->len, 0,
1808 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001809
1810 if (ret < 0) {
1811 dev_kfree_skb(beacon);
1812 goto out_sleep;
1813 }
1814
1815 hdr = (struct ieee80211_hdr *) beacon->data;
1816 hdr->frame_control = cpu_to_le16(
1817 IEEE80211_FTYPE_MGMT |
1818 IEEE80211_STYPE_PROBE_RESP);
1819
1820 ret = wl1271_cmd_template_set(wl,
1821 CMD_TEMPL_PROBE_RESPONSE,
1822 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001823 beacon->len, 0,
1824 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001825 dev_kfree_skb(beacon);
1826 if (ret < 0)
1827 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001828
1829 /* Need to update the SSID (for filtering etc) */
1830 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001831 }
1832 }
1833
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001834 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1835 (wl->bss_type == BSS_TYPE_IBSS)) {
1836 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1837 bss_conf->enable_beacon ? "enabled" : "disabled");
1838
1839 if (bss_conf->enable_beacon)
1840 wl->set_bss_type = BSS_TYPE_IBSS;
1841 else
1842 wl->set_bss_type = BSS_TYPE_STA_BSS;
1843 do_join = true;
1844 }
1845
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001846 if (changed & BSS_CHANGED_CQM) {
1847 bool enable = false;
1848 if (bss_conf->cqm_rssi_thold)
1849 enable = true;
1850 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1851 bss_conf->cqm_rssi_thold,
1852 bss_conf->cqm_rssi_hyst);
1853 if (ret < 0)
1854 goto out;
1855 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1856 }
1857
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001858 if ((changed & BSS_CHANGED_BSSID) &&
1859 /*
1860 * Now we know the correct bssid, so we send a new join command
1861 * and enable the BSSID filter
1862 */
1863 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001864 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001865
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001866 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001867 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001868 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001869
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001870 ret = wl1271_build_qos_null_data(wl);
1871 if (ret < 0)
1872 goto out_sleep;
1873
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001874 /* filter out all packets not from this BSSID */
1875 wl1271_configure_filters(wl, 0);
1876
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001877 /* Need to update the BSSID (for filtering etc) */
1878 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001879 }
1880
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881 if (changed & BSS_CHANGED_ASSOC) {
1882 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001883 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001884 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001885 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001886
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001887 wl->ps_poll_failures = 0;
1888
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001889 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001890 * use basic rates from AP, and determine lowest rate
1891 * to use with control frames.
1892 */
1893 rates = bss_conf->basic_rates;
1894 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1895 rates);
1896 wl->basic_rate = wl1271_min_rate_get(wl);
1897 ret = wl1271_acx_rate_policies(wl);
1898 if (ret < 0)
1899 goto out_sleep;
1900
1901 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001902 * with wl1271, we don't need to update the
1903 * beacon_int and dtim_period, because the firmware
1904 * updates it by itself when the first beacon is
1905 * received after a join.
1906 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001907 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1908 if (ret < 0)
1909 goto out_sleep;
1910
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001911 /*
1912 * The SSID is intentionally set to NULL here - the
1913 * firmware will set the probe request with a
1914 * broadcast SSID regardless of what we set in the
1915 * template.
1916 */
1917 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1918 NULL, 0, wl->band);
1919
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001920 /* enable the connection monitoring feature */
1921 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922 if (ret < 0)
1923 goto out_sleep;
1924
1925 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001926 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1927 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001929 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001930 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001931 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 if (ret < 0)
1933 goto out_sleep;
1934 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001935 } else {
1936 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001937 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001938 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001939 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001940
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001941 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001942 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001943
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001944 /* revert back to minimum rates for the current band */
1945 wl1271_set_band_rate(wl);
1946 wl->basic_rate = wl1271_min_rate_get(wl);
1947 ret = wl1271_acx_rate_policies(wl);
1948 if (ret < 0)
1949 goto out_sleep;
1950
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001951 /* disable connection monitor features */
1952 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001953
1954 /* Disable the keep-alive feature */
1955 ret = wl1271_acx_keep_alive_mode(wl, false);
1956
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001957 if (ret < 0)
1958 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001962
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963 if (changed & BSS_CHANGED_ERP_SLOT) {
1964 if (bss_conf->use_short_slot)
1965 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1966 else
1967 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1968 if (ret < 0) {
1969 wl1271_warning("Set slot time failed %d", ret);
1970 goto out_sleep;
1971 }
1972 }
1973
1974 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1975 if (bss_conf->use_short_preamble)
1976 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1977 else
1978 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1979 }
1980
1981 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1982 if (bss_conf->use_cts_prot)
1983 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1984 else
1985 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1986 if (ret < 0) {
1987 wl1271_warning("Set ctsprotect failed %d", ret);
1988 goto out_sleep;
1989 }
1990 }
1991
Shahar Levi18357852010-10-13 16:09:41 +02001992 /*
1993 * Takes care of: New association with HT enable,
1994 * HT information change in beacon.
1995 */
1996 if (sta &&
1997 (changed & BSS_CHANGED_HT) &&
1998 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
1999 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2000 if (ret < 0) {
2001 wl1271_warning("Set ht cap true failed %d", ret);
2002 goto out_sleep;
2003 }
2004 ret = wl1271_acx_set_ht_information(wl,
2005 bss_conf->ht_operation_mode);
2006 if (ret < 0) {
2007 wl1271_warning("Set ht information failed %d", ret);
2008 goto out_sleep;
2009 }
2010 }
2011 /*
2012 * Takes care of: New association without HT,
2013 * Disassociation.
2014 */
2015 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2016 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2017 if (ret < 0) {
2018 wl1271_warning("Set ht cap false failed %d", ret);
2019 goto out_sleep;
2020 }
2021 }
2022
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002023 if (changed & BSS_CHANGED_ARP_FILTER) {
2024 __be32 addr = bss_conf->arp_addr_list[0];
2025 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2026
2027 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
2028 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
2029 else
2030 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
2031
2032 if (ret < 0)
2033 goto out_sleep;
2034 }
2035
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002036 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002037 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002038 if (ret < 0) {
2039 wl1271_warning("cmd join failed %d", ret);
2040 goto out_sleep;
2041 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002042 }
2043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044out_sleep:
2045 wl1271_ps_elp_sleep(wl);
2046
2047out:
2048 mutex_unlock(&wl->mutex);
2049}
2050
Kalle Valoc6999d82010-02-18 13:25:41 +02002051static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2052 const struct ieee80211_tx_queue_params *params)
2053{
2054 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002055 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002056 int ret;
2057
2058 mutex_lock(&wl->mutex);
2059
2060 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2061
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002062 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2063 ret = -EAGAIN;
2064 goto out;
2065 }
2066
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002067 ret = wl1271_ps_elp_wakeup(wl, false);
2068 if (ret < 0)
2069 goto out;
2070
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002071 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002072 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2073 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002074 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002075 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002076 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002077
Kalle Valo4695dc92010-03-18 12:26:38 +02002078 if (params->uapsd)
2079 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2080 else
2081 ps_scheme = CONF_PS_SCHEME_LEGACY;
2082
Kalle Valoc6999d82010-02-18 13:25:41 +02002083 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2084 CONF_CHANNEL_TYPE_EDCF,
2085 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002086 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002087 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002088 goto out_sleep;
2089
2090out_sleep:
2091 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002092
2093out:
2094 mutex_unlock(&wl->mutex);
2095
2096 return ret;
2097}
2098
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002099static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2100{
2101
2102 struct wl1271 *wl = hw->priv;
2103 u64 mactime = ULLONG_MAX;
2104 int ret;
2105
2106 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2107
2108 mutex_lock(&wl->mutex);
2109
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002110 if (unlikely(wl->state == WL1271_STATE_OFF))
2111 goto out;
2112
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002113 ret = wl1271_ps_elp_wakeup(wl, false);
2114 if (ret < 0)
2115 goto out;
2116
2117 ret = wl1271_acx_tsf_info(wl, &mactime);
2118 if (ret < 0)
2119 goto out_sleep;
2120
2121out_sleep:
2122 wl1271_ps_elp_sleep(wl);
2123
2124out:
2125 mutex_unlock(&wl->mutex);
2126 return mactime;
2127}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128
John W. Linvilleece550d2010-07-28 16:41:06 -04002129static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2130 struct survey_info *survey)
2131{
2132 struct wl1271 *wl = hw->priv;
2133 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002134
John W. Linvilleece550d2010-07-28 16:41:06 -04002135 if (idx != 0)
2136 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002137
John W. Linvilleece550d2010-07-28 16:41:06 -04002138 survey->channel = conf->channel;
2139 survey->filled = SURVEY_INFO_NOISE_DBM;
2140 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002141
John W. Linvilleece550d2010-07-28 16:41:06 -04002142 return 0;
2143}
2144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145/* can't be const, mac80211 writes to this */
2146static struct ieee80211_rate wl1271_rates[] = {
2147 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002148 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2149 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002151 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2152 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2154 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002155 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2156 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2158 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002159 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2160 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2162 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002163 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2164 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002166 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2167 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002169 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2170 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002172 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2173 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002175 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2176 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002178 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2179 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002181 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2182 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002184 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2185 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186};
2187
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002188/*
2189 * Can't be const, mac80211 writes to this. The order of the channels here
2190 * is designed to improve scanning.
2191 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002193 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002194 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002195 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002196 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002197 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2198 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2199 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2200 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2201 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2202 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2203 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2204 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2205 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206};
2207
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002208/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002209static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002210 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002211 7, /* CONF_HW_RXTX_RATE_MCS7 */
2212 6, /* CONF_HW_RXTX_RATE_MCS6 */
2213 5, /* CONF_HW_RXTX_RATE_MCS5 */
2214 4, /* CONF_HW_RXTX_RATE_MCS4 */
2215 3, /* CONF_HW_RXTX_RATE_MCS3 */
2216 2, /* CONF_HW_RXTX_RATE_MCS2 */
2217 1, /* CONF_HW_RXTX_RATE_MCS1 */
2218 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002219
2220 11, /* CONF_HW_RXTX_RATE_54 */
2221 10, /* CONF_HW_RXTX_RATE_48 */
2222 9, /* CONF_HW_RXTX_RATE_36 */
2223 8, /* CONF_HW_RXTX_RATE_24 */
2224
2225 /* TI-specific rate */
2226 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2227
2228 7, /* CONF_HW_RXTX_RATE_18 */
2229 6, /* CONF_HW_RXTX_RATE_12 */
2230 3, /* CONF_HW_RXTX_RATE_11 */
2231 5, /* CONF_HW_RXTX_RATE_9 */
2232 4, /* CONF_HW_RXTX_RATE_6 */
2233 2, /* CONF_HW_RXTX_RATE_5_5 */
2234 1, /* CONF_HW_RXTX_RATE_2 */
2235 0 /* CONF_HW_RXTX_RATE_1 */
2236};
2237
Shahar Levie8b03a22010-10-13 16:09:39 +02002238/* 11n STA capabilities */
2239#define HW_RX_HIGHEST_RATE 72
2240
Shahar Levi18357852010-10-13 16:09:41 +02002241#ifdef CONFIG_WL1271_HT
Shahar Levie8b03a22010-10-13 16:09:39 +02002242#define WL1271_HT_CAP { \
2243 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2244 .ht_supported = true, \
2245 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2246 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2247 .mcs = { \
2248 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2249 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2250 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2251 }, \
2252}
Shahar Levi18357852010-10-13 16:09:41 +02002253#else
2254#define WL1271_HT_CAP { \
2255 .ht_supported = false, \
2256}
2257#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002259/* can't be const, mac80211 writes to this */
2260static struct ieee80211_supported_band wl1271_band_2ghz = {
2261 .channels = wl1271_channels,
2262 .n_channels = ARRAY_SIZE(wl1271_channels),
2263 .bitrates = wl1271_rates,
2264 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi18357852010-10-13 16:09:41 +02002265 .ht_cap = WL1271_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266};
2267
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002268/* 5 GHz data rates for WL1273 */
2269static struct ieee80211_rate wl1271_rates_5ghz[] = {
2270 { .bitrate = 60,
2271 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2272 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2273 { .bitrate = 90,
2274 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2275 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2276 { .bitrate = 120,
2277 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2278 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2279 { .bitrate = 180,
2280 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2281 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2282 { .bitrate = 240,
2283 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2284 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2285 { .bitrate = 360,
2286 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2287 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2288 { .bitrate = 480,
2289 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2290 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2291 { .bitrate = 540,
2292 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2293 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2294};
2295
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002296/*
2297 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2298 * The order of the channels here is designed to improve scanning.
2299 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002300static struct ieee80211_channel wl1271_channels_5ghz[] = {
2301 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002302 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002303 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002304 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002305 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002306 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002307 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002308 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002309 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002310 { .hw_value = 184, .center_freq = 4920},
2311 { .hw_value = 189, .center_freq = 4945},
2312 { .hw_value = 9, .center_freq = 5045},
2313 { .hw_value = 36, .center_freq = 5180},
2314 { .hw_value = 46, .center_freq = 5230},
2315 { .hw_value = 64, .center_freq = 5320},
2316 { .hw_value = 116, .center_freq = 5580},
2317 { .hw_value = 136, .center_freq = 5680},
2318 { .hw_value = 192, .center_freq = 4960},
2319 { .hw_value = 11, .center_freq = 5055},
2320 { .hw_value = 38, .center_freq = 5190},
2321 { .hw_value = 48, .center_freq = 5240},
2322 { .hw_value = 100, .center_freq = 5500},
2323 { .hw_value = 120, .center_freq = 5600},
2324 { .hw_value = 140, .center_freq = 5700},
2325 { .hw_value = 185, .center_freq = 4925},
2326 { .hw_value = 196, .center_freq = 4980},
2327 { .hw_value = 12, .center_freq = 5060},
2328 { .hw_value = 40, .center_freq = 5200},
2329 { .hw_value = 52, .center_freq = 5260},
2330 { .hw_value = 104, .center_freq = 5520},
2331 { .hw_value = 124, .center_freq = 5620},
2332 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002333 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002334 { .hw_value = 187, .center_freq = 4935},
2335 { .hw_value = 7, .center_freq = 5035},
2336 { .hw_value = 16, .center_freq = 5080},
2337 { .hw_value = 42, .center_freq = 5210},
2338 { .hw_value = 56, .center_freq = 5280},
2339 { .hw_value = 108, .center_freq = 5540},
2340 { .hw_value = 128, .center_freq = 5640},
2341 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002342 { .hw_value = 165, .center_freq = 5825},
2343};
2344
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002345/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002346static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002347 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002348 7, /* CONF_HW_RXTX_RATE_MCS7 */
2349 6, /* CONF_HW_RXTX_RATE_MCS6 */
2350 5, /* CONF_HW_RXTX_RATE_MCS5 */
2351 4, /* CONF_HW_RXTX_RATE_MCS4 */
2352 3, /* CONF_HW_RXTX_RATE_MCS3 */
2353 2, /* CONF_HW_RXTX_RATE_MCS2 */
2354 1, /* CONF_HW_RXTX_RATE_MCS1 */
2355 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002356
2357 7, /* CONF_HW_RXTX_RATE_54 */
2358 6, /* CONF_HW_RXTX_RATE_48 */
2359 5, /* CONF_HW_RXTX_RATE_36 */
2360 4, /* CONF_HW_RXTX_RATE_24 */
2361
2362 /* TI-specific rate */
2363 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2364
2365 3, /* CONF_HW_RXTX_RATE_18 */
2366 2, /* CONF_HW_RXTX_RATE_12 */
2367 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2368 1, /* CONF_HW_RXTX_RATE_9 */
2369 0, /* CONF_HW_RXTX_RATE_6 */
2370 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2371 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2372 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2373};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002374
2375static struct ieee80211_supported_band wl1271_band_5ghz = {
2376 .channels = wl1271_channels_5ghz,
2377 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2378 .bitrates = wl1271_rates_5ghz,
2379 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi18357852010-10-13 16:09:41 +02002380 .ht_cap = WL1271_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002381};
2382
Tobias Klausera0ea9492010-05-20 10:38:11 +02002383static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002384 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2385 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2386};
2387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388static const struct ieee80211_ops wl1271_ops = {
2389 .start = wl1271_op_start,
2390 .stop = wl1271_op_stop,
2391 .add_interface = wl1271_op_add_interface,
2392 .remove_interface = wl1271_op_remove_interface,
2393 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002394 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 .configure_filter = wl1271_op_configure_filter,
2396 .tx = wl1271_op_tx,
2397 .set_key = wl1271_op_set_key,
2398 .hw_scan = wl1271_op_hw_scan,
2399 .bss_info_changed = wl1271_op_bss_info_changed,
2400 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002401 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002402 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002403 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002404 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405};
2406
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002407
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002408u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002409{
2410 u8 idx;
2411
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002412 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002413
2414 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2415 wl1271_error("Illegal RX rate from HW: %d", rate);
2416 return 0;
2417 }
2418
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002419 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002420 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2421 wl1271_error("Unsupported RX rate from HW: %d", rate);
2422 return 0;
2423 }
2424
2425 return idx;
2426}
2427
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002428static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2429 struct device_attribute *attr,
2430 char *buf)
2431{
2432 struct wl1271 *wl = dev_get_drvdata(dev);
2433 ssize_t len;
2434
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002435 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002436
2437 mutex_lock(&wl->mutex);
2438 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2439 wl->sg_enabled);
2440 mutex_unlock(&wl->mutex);
2441
2442 return len;
2443
2444}
2445
2446static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2447 struct device_attribute *attr,
2448 const char *buf, size_t count)
2449{
2450 struct wl1271 *wl = dev_get_drvdata(dev);
2451 unsigned long res;
2452 int ret;
2453
2454 ret = strict_strtoul(buf, 10, &res);
2455
2456 if (ret < 0) {
2457 wl1271_warning("incorrect value written to bt_coex_mode");
2458 return count;
2459 }
2460
2461 mutex_lock(&wl->mutex);
2462
2463 res = !!res;
2464
2465 if (res == wl->sg_enabled)
2466 goto out;
2467
2468 wl->sg_enabled = res;
2469
2470 if (wl->state == WL1271_STATE_OFF)
2471 goto out;
2472
2473 ret = wl1271_ps_elp_wakeup(wl, false);
2474 if (ret < 0)
2475 goto out;
2476
2477 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2478 wl1271_ps_elp_sleep(wl);
2479
2480 out:
2481 mutex_unlock(&wl->mutex);
2482 return count;
2483}
2484
2485static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2486 wl1271_sysfs_show_bt_coex_state,
2487 wl1271_sysfs_store_bt_coex_state);
2488
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002489static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2490 struct device_attribute *attr,
2491 char *buf)
2492{
2493 struct wl1271 *wl = dev_get_drvdata(dev);
2494 ssize_t len;
2495
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002496 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002497
2498 mutex_lock(&wl->mutex);
2499 if (wl->hw_pg_ver >= 0)
2500 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2501 else
2502 len = snprintf(buf, len, "n/a\n");
2503 mutex_unlock(&wl->mutex);
2504
2505 return len;
2506}
2507
2508static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2509 wl1271_sysfs_show_hw_pg_ver, NULL);
2510
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002511int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512{
2513 int ret;
2514
2515 if (wl->mac80211_registered)
2516 return 0;
2517
2518 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2519
2520 ret = ieee80211_register_hw(wl->hw);
2521 if (ret < 0) {
2522 wl1271_error("unable to register mac80211 hw: %d", ret);
2523 return ret;
2524 }
2525
2526 wl->mac80211_registered = true;
2527
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002528 register_netdevice_notifier(&wl1271_dev_notifier);
2529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002530 wl1271_notice("loaded");
2531
2532 return 0;
2533}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002534EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002536void wl1271_unregister_hw(struct wl1271 *wl)
2537{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002538 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002539 ieee80211_unregister_hw(wl->hw);
2540 wl->mac80211_registered = false;
2541
2542}
2543EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2544
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002545int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002546{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002547 static const u32 cipher_suites[] = {
2548 WLAN_CIPHER_SUITE_WEP40,
2549 WLAN_CIPHER_SUITE_WEP104,
2550 WLAN_CIPHER_SUITE_TKIP,
2551 WLAN_CIPHER_SUITE_CCMP,
2552 WL1271_CIPHER_SUITE_GEM,
2553 };
2554
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002555 /* The tx descriptor buffer and the TKIP space. */
2556 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2557 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002558
2559 /* unit us */
2560 /* FIXME: find a proper value */
2561 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002562 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563
2564 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002565 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002566 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002567 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002568 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002569 IEEE80211_HW_CONNECTION_MONITOR |
2570 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002572 wl->hw->wiphy->cipher_suites = cipher_suites;
2573 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2574
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002575 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2576 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002577 wl->hw->wiphy->max_scan_ssids = 1;
2578 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002579 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002580
Kalle Valo12bd8942010-03-18 12:26:33 +02002581 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002582 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002583
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002584 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002585
2586 return 0;
2587}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002588EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002591
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002592struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002593{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002595 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002596 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002597 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002598 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599
2600 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2601 if (!hw) {
2602 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002603 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002604 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 }
2606
Julia Lawall929ebd32010-05-15 23:16:39 +02002607 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002608 if (!plat_dev) {
2609 wl1271_error("could not allocate platform_device");
2610 ret = -ENOMEM;
2611 goto err_plat_alloc;
2612 }
2613
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614 wl = hw->priv;
2615 memset(wl, 0, sizeof(*wl));
2616
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002617 INIT_LIST_HEAD(&wl->list);
2618
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002619 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002620 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002621
2622 skb_queue_head_init(&wl->tx_queue);
2623
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002624 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002625 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002626 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2627 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2628 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2629 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002631 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002632 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002633 wl->rx_counter = 0;
2634 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2635 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002636 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002638 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002639 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002640 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2641 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002642 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002643 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002644 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002645 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002646 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002648 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002649 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002650 wl->tx_frames[i] = NULL;
2651
2652 spin_lock_init(&wl->wl_lock);
2653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002654 wl->state = WL1271_STATE_OFF;
2655 mutex_init(&wl->mutex);
2656
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002657 /* Apply default driver configuration. */
2658 wl1271_conf_init(wl);
2659
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002660 wl1271_debugfs_init(wl);
2661
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002662 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2663 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2664 if (!wl->aggr_buf) {
2665 ret = -ENOMEM;
2666 goto err_hw;
2667 }
2668
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002669 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002670 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002671 if (ret) {
2672 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002673 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002674 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002675 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002676
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002677 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002678 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002679 if (ret < 0) {
2680 wl1271_error("failed to create sysfs file bt_coex_state");
2681 goto err_platform;
2682 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002683
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002684 /* Create sysfs file to get HW PG version */
2685 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2686 if (ret < 0) {
2687 wl1271_error("failed to create sysfs file hw_pg_ver");
2688 goto err_bt_coex_state;
2689 }
2690
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002691 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002692
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002693err_bt_coex_state:
2694 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2695
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002696err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002697 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002698
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002699err_aggr:
2700 free_pages((unsigned long)wl->aggr_buf, order);
2701
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002702err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002703 wl1271_debugfs_exit(wl);
2704 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002705
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002706err_plat_alloc:
2707 ieee80211_free_hw(hw);
2708
2709err_hw_alloc:
2710
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002711 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002712}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002713EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002714
2715int wl1271_free_hw(struct wl1271 *wl)
2716{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002717 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002718 free_pages((unsigned long)wl->aggr_buf,
2719 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002720 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002721
2722 wl1271_debugfs_exit(wl);
2723
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002724 vfree(wl->fw);
2725 wl->fw = NULL;
2726 kfree(wl->nvs);
2727 wl->nvs = NULL;
2728
2729 kfree(wl->fw_status);
2730 kfree(wl->tx_res_if);
2731
2732 ieee80211_free_hw(wl->hw);
2733
2734 return 0;
2735}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002736EXPORT_SYMBOL_GPL(wl1271_free_hw);
2737
2738MODULE_LICENSE("GPL");
2739MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2740MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");