blob: c54887c806462d6a95fdb661e1cd515e41adc4cb [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200217 .psm_entry_retries = 5,
218 .psm_entry_nullfunc_retries = 3,
219 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300220 .keep_alive_interval = 55000,
221 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200223 .itrim = {
224 .enable = false,
225 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200226 },
227 .pm_config = {
228 .host_clk_settling_time = 5000,
229 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 },
231 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300232 .trigger_pacing = 1,
233 .avg_weight_rssi_beacon = 20,
234 .avg_weight_rssi_data = 10,
235 .avg_weight_snr_beacon = 20,
236 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200237 },
238 .scan = {
239 .min_dwell_time_active = 7500,
240 .max_dwell_time_active = 30000,
241 .min_dwell_time_passive = 30000,
242 .max_dwell_time_passive = 60000,
243 .num_probe_reqs = 2,
244 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200245 .rf = {
246 .tx_per_channel_power_compensation_2 = {
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 },
249 .tx_per_channel_power_compensation_5 = {
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 },
254 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255};
256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200257static void __wl1271_op_remove_interface(struct wl1271 *wl);
258
259
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200260static void wl1271_device_release(struct device *dev)
261{
262
263}
264
265static struct platform_device wl1271_device = {
266 .name = "wl1271",
267 .id = -1,
268
269 /* device model insists to have a release function */
270 .dev = {
271 .release = wl1271_device_release,
272 },
273};
274
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300275static LIST_HEAD(wl_list);
276
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300277static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
278 void *arg)
279{
280 struct net_device *dev = arg;
281 struct wireless_dev *wdev;
282 struct wiphy *wiphy;
283 struct ieee80211_hw *hw;
284 struct wl1271 *wl;
285 struct wl1271 *wl_temp;
286 int ret = 0;
287
288 /* Check that this notification is for us. */
289 if (what != NETDEV_CHANGE)
290 return NOTIFY_DONE;
291
292 wdev = dev->ieee80211_ptr;
293 if (wdev == NULL)
294 return NOTIFY_DONE;
295
296 wiphy = wdev->wiphy;
297 if (wiphy == NULL)
298 return NOTIFY_DONE;
299
300 hw = wiphy_priv(wiphy);
301 if (hw == NULL)
302 return NOTIFY_DONE;
303
304 wl_temp = hw->priv;
305 list_for_each_entry(wl, &wl_list, list) {
306 if (wl == wl_temp)
307 break;
308 }
309 if (wl != wl_temp)
310 return NOTIFY_DONE;
311
312 mutex_lock(&wl->mutex);
313
314 if (wl->state == WL1271_STATE_OFF)
315 goto out;
316
317 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
318 goto out;
319
320 ret = wl1271_ps_elp_wakeup(wl, false);
321 if (ret < 0)
322 goto out;
323
324 if ((dev->operstate == IF_OPER_UP) &&
325 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
326 wl1271_cmd_set_sta_state(wl);
327 wl1271_info("Association completed.");
328 }
329
330 wl1271_ps_elp_sleep(wl);
331
332out:
333 mutex_unlock(&wl->mutex);
334
335 return NOTIFY_OK;
336}
337
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338static void wl1271_conf_init(struct wl1271 *wl)
339{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340
341 /*
342 * This function applies the default configuration to the driver. This
343 * function is invoked upon driver load (spi probe.)
344 *
345 * The configuration is stored in a run-time structure in order to
346 * facilitate for run-time adjustment of any of the parameters. Making
347 * changes to the configuration structure will apply the new values on
348 * the next interface up (wl1271_op_start.)
349 */
350
351 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300352 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300353}
354
355
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300356static int wl1271_plt_init(struct wl1271 *wl)
357{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200358 struct conf_tx_ac_category *conf_ac;
359 struct conf_tx_tid *conf_tid;
360 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200362 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200363 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200364 return ret;
365
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200366 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200367 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200368 return ret;
369
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200370 ret = wl1271_cmd_ext_radio_parms(wl);
371 if (ret < 0)
372 return ret;
373
Luciano Coelho12419cc2010-02-18 13:25:44 +0200374 ret = wl1271_init_templates_config(wl);
375 if (ret < 0)
376 return ret;
377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 ret = wl1271_acx_init_mem_config(wl);
379 if (ret < 0)
380 return ret;
381
Luciano Coelho12419cc2010-02-18 13:25:44 +0200382 /* PHY layer config */
383 ret = wl1271_init_phy_config(wl);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 ret = wl1271_acx_dco_itrim_params(wl);
388 if (ret < 0)
389 goto out_free_memmap;
390
391 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200392 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200393 if (ret < 0)
394 goto out_free_memmap;
395
396 /* Bluetooth WLAN coexistence */
397 ret = wl1271_init_pta(wl);
398 if (ret < 0)
399 goto out_free_memmap;
400
401 /* Energy detection */
402 ret = wl1271_init_energy_detection(wl);
403 if (ret < 0)
404 goto out_free_memmap;
405
406 /* Default fragmentation threshold */
407 ret = wl1271_acx_frag_threshold(wl);
408 if (ret < 0)
409 goto out_free_memmap;
410
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200411 /* Default TID/AC configuration */
412 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200413 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200414 conf_ac = &wl->conf.tx.ac_conf[i];
415 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
416 conf_ac->cw_max, conf_ac->aifsn,
417 conf_ac->tx_op_limit);
418 if (ret < 0)
419 goto out_free_memmap;
420
Luciano Coelho12419cc2010-02-18 13:25:44 +0200421 conf_tid = &wl->conf.tx.tid_conf[i];
422 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
423 conf_tid->channel_type,
424 conf_tid->tsid,
425 conf_tid->ps_scheme,
426 conf_tid->ack_policy,
427 conf_tid->apsd_conf[0],
428 conf_tid->apsd_conf[1]);
429 if (ret < 0)
430 goto out_free_memmap;
431 }
432
Luciano Coelho12419cc2010-02-18 13:25:44 +0200433 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200434 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200436 goto out_free_memmap;
437
438 /* Configure for CAM power saving (ie. always active) */
439 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
440 if (ret < 0)
441 goto out_free_memmap;
442
443 /* configure PM */
444 ret = wl1271_acx_pm_config(wl);
445 if (ret < 0)
446 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
448 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200449
450 out_free_memmap:
451 kfree(wl->target_mem_map);
452 wl->target_mem_map = NULL;
453
454 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455}
456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457static void wl1271_fw_status(struct wl1271 *wl,
458 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200460 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 u32 total = 0;
462 int i;
463
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200464 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
467 "drv_rx_counter = %d, tx_results_counter = %d)",
468 status->intr,
469 status->fw_rx_counter,
470 status->drv_rx_counter,
471 status->tx_results_counter);
472
473 /* update number of available TX blocks */
474 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300475 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
476 wl->tx_blocks_freed[i];
477
478 wl->tx_blocks_freed[i] =
479 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl->tx_blocks_available += cnt;
481 total += cnt;
482 }
483
Ido Yariva5225502010-10-12 14:49:10 +0200484 /* if more blocks are available now, tx work can be scheduled */
485 if (total)
486 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200489 getnstimeofday(&ts);
490 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
491 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492}
493
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200494#define WL1271_IRQ_MAX_LOOPS 10
495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496static void wl1271_irq_work(struct work_struct *work)
497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300499 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200500 int loopcount = WL1271_IRQ_MAX_LOOPS;
501 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 struct wl1271 *wl =
503 container_of(work, struct wl1271, irq_work);
504
505 mutex_lock(&wl->mutex);
506
507 wl1271_debug(DEBUG_IRQ, "IRQ work");
508
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 goto out;
511
512 ret = wl1271_ps_elp_wakeup(wl, true);
513 if (ret < 0)
514 goto out;
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516 spin_lock_irqsave(&wl->wl_lock, flags);
517 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
518 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520 loopcount--;
521
522 wl1271_fw_status(wl, wl->fw_status);
523 intr = le32_to_cpu(wl->fw_status->intr);
524 if (!intr) {
525 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200526 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200527 continue;
528 }
529
530 intr &= WL1271_INTR_MASK;
531
532 if (intr & WL1271_ACX_INTR_DATA) {
533 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
534
535 /* check for tx results */
536 if (wl->fw_status->tx_results_counter !=
537 (wl->tx_results_count & 0xff))
538 wl1271_tx_complete(wl);
539
Ido Yariva5225502010-10-12 14:49:10 +0200540 /* Check if any tx blocks were freed */
541 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
542 !skb_queue_empty(&wl->tx_queue)) {
543 /*
544 * In order to avoid starvation of the TX path,
545 * call the work function directly.
546 */
547 wl1271_tx_work_locked(wl);
548 }
549
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200550 wl1271_rx(wl, wl->fw_status);
551 }
552
553 if (intr & WL1271_ACX_INTR_EVENT_A) {
554 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
555 wl1271_event_handle(wl, 0);
556 }
557
558 if (intr & WL1271_ACX_INTR_EVENT_B) {
559 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
560 wl1271_event_handle(wl, 1);
561 }
562
563 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
564 wl1271_debug(DEBUG_IRQ,
565 "WL1271_ACX_INTR_INIT_COMPLETE");
566
567 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
568 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
569
570 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300571 }
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
574 ieee80211_queue_work(wl->hw, &wl->irq_work);
575 else
576 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
577 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 wl1271_ps_elp_sleep(wl);
580
581out:
582 mutex_unlock(&wl->mutex);
583}
584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585static int wl1271_fetch_firmware(struct wl1271 *wl)
586{
587 const struct firmware *fw;
588 int ret;
589
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200590 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
592 if (ret < 0) {
593 wl1271_error("could not get firmware: %d", ret);
594 return ret;
595 }
596
597 if (fw->size % 4) {
598 wl1271_error("firmware size is not multiple of 32 bits: %zu",
599 fw->size);
600 ret = -EILSEQ;
601 goto out;
602 }
603
604 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300605 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606
607 if (!wl->fw) {
608 wl1271_error("could not allocate memory for the firmware");
609 ret = -ENOMEM;
610 goto out;
611 }
612
613 memcpy(wl->fw, fw->data, wl->fw_len);
614
615 ret = 0;
616
617out:
618 release_firmware(fw);
619
620 return ret;
621}
622
623static int wl1271_fetch_nvs(struct wl1271 *wl)
624{
625 const struct firmware *fw;
626 int ret;
627
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200628 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629
630 if (ret < 0) {
631 wl1271_error("could not get nvs file: %d", ret);
632 return ret;
633 }
634
Julia Lawall929ebd32010-05-15 23:16:39 +0200635 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 if (!wl->nvs) {
638 wl1271_error("could not allocate memory for the nvs file");
639 ret = -ENOMEM;
640 goto out;
641 }
642
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200643 wl->nvs_len = fw->size;
644
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645out:
646 release_firmware(fw);
647
648 return ret;
649}
650
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200651static void wl1271_recovery_work(struct work_struct *work)
652{
653 struct wl1271 *wl =
654 container_of(work, struct wl1271, recovery_work);
655
656 mutex_lock(&wl->mutex);
657
658 if (wl->state != WL1271_STATE_ON)
659 goto out;
660
661 wl1271_info("Hardware recovery in progress.");
662
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200663 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
664 ieee80211_connection_loss(wl->vif);
665
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200666 /* reboot the chipset */
667 __wl1271_op_remove_interface(wl);
668 ieee80211_restart_hw(wl->hw);
669
670out:
671 mutex_unlock(&wl->mutex);
672}
673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674static void wl1271_fw_wakeup(struct wl1271 *wl)
675{
676 u32 elp_reg;
677
678 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300679 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680}
681
682static int wl1271_setup(struct wl1271 *wl)
683{
684 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
685 if (!wl->fw_status)
686 return -ENOMEM;
687
688 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
689 if (!wl->tx_res_if) {
690 kfree(wl->fw_status);
691 return -ENOMEM;
692 }
693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 return 0;
695}
696
697static int wl1271_chip_wakeup(struct wl1271 *wl)
698{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300699 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 int ret = 0;
701
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200702 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200703 ret = wl1271_power_on(wl);
704 if (ret < 0)
705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200707 wl1271_io_reset(wl);
708 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
710 /* We don't need a real memory partition here, because we only want
711 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300712 memset(&partition, 0, sizeof(partition));
713 partition.reg.start = REGISTERS_BASE;
714 partition.reg.size = REGISTERS_DOWN_SIZE;
715 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716
717 /* ELP module wake up */
718 wl1271_fw_wakeup(wl);
719
720 /* whal_FwCtrl_BootSm() */
721
722 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200723 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724
725 /* 1. check if chip id is valid */
726
727 switch (wl->chip.id) {
728 case CHIP_ID_1271_PG10:
729 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
730 wl->chip.id);
731
732 ret = wl1271_setup(wl);
733 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 break;
736 case CHIP_ID_1271_PG20:
737 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
738 wl->chip.id);
739
740 ret = wl1271_setup(wl);
741 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 break;
744 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748 }
749
750 if (wl->fw == NULL) {
751 ret = wl1271_fetch_firmware(wl);
752 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200753 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 }
755
756 /* No NVS from netlink, try to get it from the filesystem */
757 if (wl->nvs == NULL) {
758 ret = wl1271_fetch_nvs(wl);
759 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200760 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761 }
762
763out:
764 return ret;
765}
766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767int wl1271_plt_start(struct wl1271 *wl)
768{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200769 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 int ret;
771
772 mutex_lock(&wl->mutex);
773
774 wl1271_notice("power up");
775
776 if (wl->state != WL1271_STATE_OFF) {
777 wl1271_error("cannot go into PLT state because not "
778 "in off state: %d", wl->state);
779 ret = -EBUSY;
780 goto out;
781 }
782
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200783 while (retries) {
784 retries--;
785 ret = wl1271_chip_wakeup(wl);
786 if (ret < 0)
787 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200789 ret = wl1271_boot(wl);
790 if (ret < 0)
791 goto power_off;
792
793 ret = wl1271_plt_init(wl);
794 if (ret < 0)
795 goto irq_disable;
796
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200797 wl->state = WL1271_STATE_PLT;
798 wl1271_notice("firmware booted in PLT mode (%s)",
799 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800 goto out;
801
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200802irq_disable:
803 wl1271_disable_interrupts(wl);
804 mutex_unlock(&wl->mutex);
805 /* Unlocking the mutex in the middle of handling is
806 inherently unsafe. In this case we deem it safe to do,
807 because we need to let any possibly pending IRQ out of
808 the system (and while we are WL1271_STATE_OFF the IRQ
809 work function will not do anything.) Also, any other
810 possible concurrent operations will fail due to the
811 current state, hence the wl1271 struct should be safe. */
812 cancel_work_sync(&wl->irq_work);
813 mutex_lock(&wl->mutex);
814power_off:
815 wl1271_power_off(wl);
816 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200818 wl1271_error("firmware boot in PLT mode failed despite %d retries",
819 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820out:
821 mutex_unlock(&wl->mutex);
822
823 return ret;
824}
825
826int wl1271_plt_stop(struct wl1271 *wl)
827{
828 int ret = 0;
829
830 mutex_lock(&wl->mutex);
831
832 wl1271_notice("power down");
833
834 if (wl->state != WL1271_STATE_PLT) {
835 wl1271_error("cannot power down because not in PLT "
836 "state: %d", wl->state);
837 ret = -EBUSY;
838 goto out;
839 }
840
841 wl1271_disable_interrupts(wl);
842 wl1271_power_off(wl);
843
844 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300845 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846
847out:
848 mutex_unlock(&wl->mutex);
849
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200850 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200851 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 return ret;
854}
855
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
857{
858 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200859 struct ieee80211_conf *conf = &hw->conf;
860 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
861 struct ieee80211_sta *sta = txinfo->control.sta;
862 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863
Shahar Levi18357852010-10-13 16:09:41 +0200864 /*
865 * peek into the rates configured in the STA entry.
866 * The rates set after connection stage, The first block only BG sets:
867 * the compare is for bit 0-16 of sta_rate_set. The second block add
868 * HT rates in case of HT supported.
869 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200870 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200871 if (sta &&
872 (sta->supp_rates[conf->channel->band] !=
873 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200874 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
875 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
876 }
Shahar Levi18357852010-10-13 16:09:41 +0200877
878#ifdef CONFIG_WL1271_HT
879 if (sta &&
880 sta->ht_cap.ht_supported &&
881 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
882 sta->ht_cap.mcs.rx_mask[0])) {
883 /* Clean MCS bits before setting them */
884 wl->sta_rate_set &= HW_BG_RATES_MASK;
885 wl->sta_rate_set |=
886 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
887 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
888 }
889#endif
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200890 spin_unlock_irqrestore(&wl->wl_lock, flags);
891
892 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 skb_queue_tail(&wl->tx_queue, skb);
894
895 /*
896 * The chip specific setup must run before the first TX packet -
897 * before that, the tx_work will not be initialized!
898 */
899
Ido Yariva5225502010-10-12 14:49:10 +0200900 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
901 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 /*
904 * The workqueue is slow to process the tx_queue and we need stop
905 * the queue here, otherwise the queue will get too long.
906 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200907 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
908 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200910 spin_lock_irqsave(&wl->wl_lock, flags);
911 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200912 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200913 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914 }
915
916 return NETDEV_TX_OK;
917}
918
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300919static struct notifier_block wl1271_dev_notifier = {
920 .notifier_call = wl1271_dev_notify,
921};
922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923static int wl1271_op_start(struct ieee80211_hw *hw)
924{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200925 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
926
927 /*
928 * We have to delay the booting of the hardware because
929 * we need to know the local MAC address before downloading and
930 * initializing the firmware. The MAC address cannot be changed
931 * after boot, and without the proper MAC address, the firmware
932 * will not function properly.
933 *
934 * The MAC address is first known when the corresponding interface
935 * is added. That is where we will initialize the hardware.
936 */
937
938 return 0;
939}
940
941static void wl1271_op_stop(struct ieee80211_hw *hw)
942{
943 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
944}
945
946static int wl1271_op_add_interface(struct ieee80211_hw *hw,
947 struct ieee80211_vif *vif)
948{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400950 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200951 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952 int ret = 0;
953
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200954 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
955 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
957 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200958 if (wl->vif) {
959 ret = -EBUSY;
960 goto out;
961 }
962
963 wl->vif = vif;
964
965 switch (vif->type) {
966 case NL80211_IFTYPE_STATION:
967 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200968 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200969 break;
970 case NL80211_IFTYPE_ADHOC:
971 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200972 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200973 break;
974 default:
975 ret = -EOPNOTSUPP;
976 goto out;
977 }
978
979 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980
981 if (wl->state != WL1271_STATE_OFF) {
982 wl1271_error("cannot start because not in off state: %d",
983 wl->state);
984 ret = -EBUSY;
985 goto out;
986 }
987
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988 while (retries) {
989 retries--;
990 ret = wl1271_chip_wakeup(wl);
991 if (ret < 0)
992 goto power_off;
993
994 ret = wl1271_boot(wl);
995 if (ret < 0)
996 goto power_off;
997
998 ret = wl1271_hw_init(wl);
999 if (ret < 0)
1000 goto irq_disable;
1001
1002 wl->state = WL1271_STATE_ON;
1003 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -04001004
1005 /* update hw/fw version info in wiphy struct */
1006 wiphy->hw_version = wl->chip.id;
1007 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1008 sizeof(wiphy->fw_version));
1009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 goto out;
1011
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001012irq_disable:
1013 wl1271_disable_interrupts(wl);
1014 mutex_unlock(&wl->mutex);
1015 /* Unlocking the mutex in the middle of handling is
1016 inherently unsafe. In this case we deem it safe to do,
1017 because we need to let any possibly pending IRQ out of
1018 the system (and while we are WL1271_STATE_OFF the IRQ
1019 work function will not do anything.) Also, any other
1020 possible concurrent operations will fail due to the
1021 current state, hence the wl1271 struct should be safe. */
1022 cancel_work_sync(&wl->irq_work);
1023 mutex_lock(&wl->mutex);
1024power_off:
1025 wl1271_power_off(wl);
1026 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001028 wl1271_error("firmware boot failed despite %d retries",
1029 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001030out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 mutex_unlock(&wl->mutex);
1032
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001033 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001034 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 return ret;
1037}
1038
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001039static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 int i;
1042
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001043 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001045 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001047 list_del(&wl->list);
1048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 WARN_ON(wl->state != WL1271_STATE_ON);
1050
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001051 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001052 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001053 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001054
Luciano Coelho08688d62010-07-08 17:50:07 +03001055 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001056 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1057 kfree(wl->scan.scanned_ch);
1058 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001059 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001060 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 }
1062
1063 wl->state = WL1271_STATE_OFF;
1064
1065 wl1271_disable_interrupts(wl);
1066
1067 mutex_unlock(&wl->mutex);
1068
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001069 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 cancel_work_sync(&wl->irq_work);
1071 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001072 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001073 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074
1075 mutex_lock(&wl->mutex);
1076
1077 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001078 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl1271_power_off(wl);
1080
1081 memset(wl->bssid, 0, ETH_ALEN);
1082 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1083 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001085 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001086 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
1088 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001089 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1091 wl->tx_blocks_available = 0;
1092 wl->tx_results_count = 0;
1093 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001094 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001095 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 wl->time_offset = 0;
1097 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001098 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1099 wl->sta_rate_set = 0;
1100 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001101 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001102 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 for (i = 0; i < NUM_TX_QUEUES; i++)
1105 wl->tx_blocks_freed[i] = 0;
1106
1107 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001108
1109 kfree(wl->fw_status);
1110 wl->fw_status = NULL;
1111 kfree(wl->tx_res_if);
1112 wl->tx_res_if = NULL;
1113 kfree(wl->target_mem_map);
1114 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001115}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001116
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001117static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1118 struct ieee80211_vif *vif)
1119{
1120 struct wl1271 *wl = hw->priv;
1121
1122 mutex_lock(&wl->mutex);
1123 WARN_ON(wl->vif != vif);
1124 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001126
1127 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128}
1129
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001130static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1131{
1132 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1133 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1134
1135 /* combine requested filters with current filter config */
1136 filters = wl->filters | filters;
1137
1138 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1139
1140 if (filters & FIF_PROMISC_IN_BSS) {
1141 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1142 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1143 wl->rx_config |= CFG_BSSID_FILTER_EN;
1144 }
1145 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1146 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1147 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1148 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1149 }
1150 if (filters & FIF_OTHER_BSS) {
1151 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1152 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1153 }
1154 if (filters & FIF_CONTROL) {
1155 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1156 wl->rx_filter |= CFG_RX_CTL_EN;
1157 }
1158 if (filters & FIF_FCSFAIL) {
1159 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1160 wl->rx_filter |= CFG_RX_FCS_ERROR;
1161 }
1162}
1163
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001164static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001165{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001166 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001167 /* we need to use a dummy BSSID for now */
1168 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1169 0xad, 0xbe, 0xef };
1170
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001171 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1172
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001173 /* pass through frames from all BSS */
1174 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1175
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001176 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001177 if (ret < 0)
1178 goto out;
1179
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001180 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001181
1182out:
1183 return ret;
1184}
1185
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001186static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001187{
1188 int ret;
1189
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001190 /*
1191 * One of the side effects of the JOIN command is that is clears
1192 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1193 * to a WPA/WPA2 access point will therefore kill the data-path.
1194 * Currently there is no supported scenario for JOIN during
1195 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1196 * must be handled somehow.
1197 *
1198 */
1199 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1200 wl1271_info("JOIN while associated.");
1201
1202 if (set_assoc)
1203 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1204
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001205 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1206 if (ret < 0)
1207 goto out;
1208
1209 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1210
1211 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1212 goto out;
1213
1214 /*
1215 * The join command disable the keep-alive mode, shut down its process,
1216 * and also clear the template config, so we need to reset it all after
1217 * the join. The acx_aid starts the keep-alive process, and the order
1218 * of the commands below is relevant.
1219 */
1220 ret = wl1271_acx_keep_alive_mode(wl, true);
1221 if (ret < 0)
1222 goto out;
1223
1224 ret = wl1271_acx_aid(wl, wl->aid);
1225 if (ret < 0)
1226 goto out;
1227
1228 ret = wl1271_cmd_build_klv_null_data(wl);
1229 if (ret < 0)
1230 goto out;
1231
1232 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1233 ACX_KEEP_ALIVE_TPL_VALID);
1234 if (ret < 0)
1235 goto out;
1236
1237out:
1238 return ret;
1239}
1240
1241static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001242{
1243 int ret;
1244
1245 /* to stop listening to a channel, we disconnect */
1246 ret = wl1271_cmd_disconnect(wl);
1247 if (ret < 0)
1248 goto out;
1249
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001250 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001251 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001252
1253 /* stop filterting packets based on bssid */
1254 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001255
1256out:
1257 return ret;
1258}
1259
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001260static void wl1271_set_band_rate(struct wl1271 *wl)
1261{
1262 if (wl->band == IEEE80211_BAND_2GHZ)
1263 wl->basic_rate_set = wl->conf.tx.basic_rate;
1264 else
1265 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1266}
1267
1268static u32 wl1271_min_rate_get(struct wl1271 *wl)
1269{
1270 int i;
1271 u32 rate = 0;
1272
1273 if (!wl->basic_rate_set) {
1274 WARN_ON(1);
1275 wl->basic_rate_set = wl->conf.tx.basic_rate;
1276 }
1277
1278 for (i = 0; !rate; i++) {
1279 if ((wl->basic_rate_set >> i) & 0x1)
1280 rate = 1 << i;
1281 }
1282
1283 return rate;
1284}
1285
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001286static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1287{
1288 int ret;
1289
1290 if (idle) {
1291 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1292 ret = wl1271_unjoin(wl);
1293 if (ret < 0)
1294 goto out;
1295 }
1296 wl->rate_set = wl1271_min_rate_get(wl);
1297 wl->sta_rate_set = 0;
1298 ret = wl1271_acx_rate_policies(wl);
1299 if (ret < 0)
1300 goto out;
1301 ret = wl1271_acx_keep_alive_config(
1302 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1303 ACX_KEEP_ALIVE_TPL_INVALID);
1304 if (ret < 0)
1305 goto out;
1306 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1307 } else {
1308 /* increment the session counter */
1309 wl->session_counter++;
1310 if (wl->session_counter >= SESSION_COUNTER_MAX)
1311 wl->session_counter = 0;
1312 ret = wl1271_dummy_join(wl);
1313 if (ret < 0)
1314 goto out;
1315 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1316 }
1317
1318out:
1319 return ret;
1320}
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1323{
1324 struct wl1271 *wl = hw->priv;
1325 struct ieee80211_conf *conf = &hw->conf;
1326 int channel, ret = 0;
1327
1328 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1329
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001330 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 channel,
1332 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001333 conf->power_level,
1334 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001336 /*
1337 * mac80211 will go to idle nearly immediately after transmitting some
1338 * frames, such as the deauth. To make sure those frames reach the air,
1339 * wait here until the TX queue is fully flushed.
1340 */
1341 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1342 (conf->flags & IEEE80211_CONF_IDLE))
1343 wl1271_tx_flush(wl);
1344
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 mutex_lock(&wl->mutex);
1346
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001347 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1348 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001349 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001350 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 ret = wl1271_ps_elp_wakeup(wl, false);
1353 if (ret < 0)
1354 goto out;
1355
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001356 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001357 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1358 ((wl->band != conf->channel->band) ||
1359 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001360 wl->band = conf->channel->band;
1361 wl->channel = channel;
1362
1363 /*
1364 * FIXME: the mac80211 should really provide a fixed rate
1365 * to use here. for now, just use the smallest possible rate
1366 * for the band as a fixed rate for association frames and
1367 * other control messages.
1368 */
1369 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1370 wl1271_set_band_rate(wl);
1371
1372 wl->basic_rate = wl1271_min_rate_get(wl);
1373 ret = wl1271_acx_rate_policies(wl);
1374 if (ret < 0)
1375 wl1271_warning("rate policy for update channel "
1376 "failed %d", ret);
1377
1378 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001379 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001380 if (ret < 0)
1381 wl1271_warning("cmd join to update channel "
1382 "failed %d", ret);
1383 }
1384 }
1385
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001386 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001387 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1388 if (ret < 0)
1389 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390 }
1391
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001392 /*
1393 * if mac80211 changes the PSM mode, make sure the mode is not
1394 * incorrectly changed after the pspoll failure active window.
1395 */
1396 if (changed & IEEE80211_CONF_CHANGE_PS)
1397 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1398
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001399 if (conf->flags & IEEE80211_CONF_PS &&
1400 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1401 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
1403 /*
1404 * We enter PSM only if we're already associated.
1405 * If we're not, we'll enter it when joining an SSID,
1406 * through the bss_info_changed() hook.
1407 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001408 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001409 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001410 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001411 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001412 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001414 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001415 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001416
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001417 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001419 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001420 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001421 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422 }
1423
1424 if (conf->power_level != wl->power_level) {
1425 ret = wl1271_acx_tx_power(wl, conf->power_level);
1426 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001427 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
1429 wl->power_level = conf->power_level;
1430 }
1431
1432out_sleep:
1433 wl1271_ps_elp_sleep(wl);
1434
1435out:
1436 mutex_unlock(&wl->mutex);
1437
1438 return ret;
1439}
1440
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001441struct wl1271_filter_params {
1442 bool enabled;
1443 int mc_list_length;
1444 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1445};
1446
Jiri Pirko22bedad32010-04-01 21:22:57 +00001447static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1448 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001449{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001450 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001451 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001452 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001453
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001454 if (unlikely(wl->state == WL1271_STATE_OFF))
1455 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001456
Juuso Oikarinen74441132009-10-13 12:47:53 +03001457 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001458 if (!fp) {
1459 wl1271_error("Out of memory setting filters.");
1460 return 0;
1461 }
1462
1463 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001464 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001465 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1466 fp->enabled = false;
1467 } else {
1468 fp->enabled = true;
1469 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001470 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001471 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001472 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001473 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001474 }
1475
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001476 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001477}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001479#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1480 FIF_ALLMULTI | \
1481 FIF_FCSFAIL | \
1482 FIF_BCN_PRBRESP_PROMISC | \
1483 FIF_CONTROL | \
1484 FIF_OTHER_BSS)
1485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1487 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001488 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001490 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001492 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493
1494 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1495
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001496 mutex_lock(&wl->mutex);
1497
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001498 *total &= WL1271_SUPPORTED_FILTERS;
1499 changed &= WL1271_SUPPORTED_FILTERS;
1500
1501 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001502 goto out;
1503
1504 ret = wl1271_ps_elp_wakeup(wl, false);
1505 if (ret < 0)
1506 goto out;
1507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001509 if (*total & FIF_ALLMULTI)
1510 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1511 else if (fp)
1512 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1513 fp->mc_list,
1514 fp->mc_list_length);
1515 if (ret < 0)
1516 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001518 /* determine, whether supported filter values have changed */
1519 if (changed == 0)
1520 goto out_sleep;
1521
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001522 /* configure filters */
1523 wl->filters = *total;
1524 wl1271_configure_filters(wl, 0);
1525
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001526 /* apply configured filters */
1527 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1528 if (ret < 0)
1529 goto out_sleep;
1530
1531out_sleep:
1532 wl1271_ps_elp_sleep(wl);
1533
1534out:
1535 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001536 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537}
1538
1539static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1540 struct ieee80211_vif *vif,
1541 struct ieee80211_sta *sta,
1542 struct ieee80211_key_conf *key_conf)
1543{
1544 struct wl1271 *wl = hw->priv;
1545 const u8 *addr;
1546 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001547 u32 tx_seq_32 = 0;
1548 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001549 u8 key_type;
1550
1551 static const u8 bcast_addr[ETH_ALEN] =
1552 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1553
1554 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1555
1556 addr = sta ? sta->addr : bcast_addr;
1557
1558 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1559 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1560 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001561 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562 key_conf->keylen, key_conf->flags);
1563 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1564
1565 if (is_zero_ether_addr(addr)) {
1566 /* We dont support TX only encryption */
1567 ret = -EOPNOTSUPP;
1568 goto out;
1569 }
1570
1571 mutex_lock(&wl->mutex);
1572
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001573 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1574 ret = -EAGAIN;
1575 goto out_unlock;
1576 }
1577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 ret = wl1271_ps_elp_wakeup(wl, false);
1579 if (ret < 0)
1580 goto out_unlock;
1581
Johannes Berg97359d12010-08-10 09:46:38 +02001582 switch (key_conf->cipher) {
1583 case WLAN_CIPHER_SUITE_WEP40:
1584 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 key_type = KEY_WEP;
1586
1587 key_conf->hw_key_idx = key_conf->keyidx;
1588 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001589 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 key_type = KEY_TKIP;
1591
1592 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001593 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1594 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001596 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597 key_type = KEY_AES;
1598
1599 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
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;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001603 case WL1271_CIPHER_SUITE_GEM:
1604 key_type = KEY_GEM;
1605 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1606 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1607 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001609 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
1611 ret = -EOPNOTSUPP;
1612 goto out_sleep;
1613 }
1614
1615 switch (cmd) {
1616 case SET_KEY:
1617 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1618 key_conf->keyidx, key_type,
1619 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001620 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001621 if (ret < 0) {
1622 wl1271_error("Could not add or replace key");
1623 goto out_sleep;
1624 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001625
1626 /* the default WEP key needs to be configured at least once */
1627 if (key_type == KEY_WEP) {
1628 ret = wl1271_cmd_set_default_wep_key(wl,
1629 wl->default_key);
1630 if (ret < 0)
1631 goto out_sleep;
1632 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001633 break;
1634
1635 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001636 /* The wl1271 does not allow to remove unicast keys - they
1637 will be cleared automatically on next CMD_JOIN. Ignore the
1638 request silently, as we dont want the mac80211 to emit
1639 an error message. */
1640 if (!is_broadcast_ether_addr(addr))
1641 break;
1642
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001643 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1644 key_conf->keyidx, key_type,
1645 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001646 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647 if (ret < 0) {
1648 wl1271_error("Could not remove key");
1649 goto out_sleep;
1650 }
1651 break;
1652
1653 default:
1654 wl1271_error("Unsupported key cmd 0x%x", cmd);
1655 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656 break;
1657 }
1658
1659out_sleep:
1660 wl1271_ps_elp_sleep(wl);
1661
1662out_unlock:
1663 mutex_unlock(&wl->mutex);
1664
1665out:
1666 return ret;
1667}
1668
1669static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001670 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001671 struct cfg80211_scan_request *req)
1672{
1673 struct wl1271 *wl = hw->priv;
1674 int ret;
1675 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001676 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677
1678 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1679
1680 if (req->n_ssids) {
1681 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001682 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683 }
1684
1685 mutex_lock(&wl->mutex);
1686
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001687 if (wl->state == WL1271_STATE_OFF) {
1688 /*
1689 * We cannot return -EBUSY here because cfg80211 will expect
1690 * a call to ieee80211_scan_completed if we do - in this case
1691 * there won't be any call.
1692 */
1693 ret = -EAGAIN;
1694 goto out;
1695 }
1696
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 ret = wl1271_ps_elp_wakeup(wl, false);
1698 if (ret < 0)
1699 goto out;
1700
Luciano Coelho5924f892010-08-04 03:46:22 +03001701 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702
1703 wl1271_ps_elp_sleep(wl);
1704
1705out:
1706 mutex_unlock(&wl->mutex);
1707
1708 return ret;
1709}
1710
1711static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1712{
1713 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001714 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715
1716 mutex_lock(&wl->mutex);
1717
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001718 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1719 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001720 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001721 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001722
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 ret = wl1271_ps_elp_wakeup(wl, false);
1724 if (ret < 0)
1725 goto out;
1726
1727 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1728 if (ret < 0)
1729 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1730
1731 wl1271_ps_elp_sleep(wl);
1732
1733out:
1734 mutex_unlock(&wl->mutex);
1735
1736 return ret;
1737}
1738
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001739static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1740{
1741 u8 *ptr = beacon->data +
1742 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1743
1744 /* find the location of the ssid in the beacon */
1745 while (ptr < beacon->data + beacon->len) {
1746 if (ptr[0] == WLAN_EID_SSID) {
1747 wl->ssid_len = ptr[1];
1748 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1749 return;
1750 }
1751 ptr += ptr[1];
1752 }
1753 wl1271_error("ad-hoc beacon template has no SSID!\n");
1754}
1755
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1757 struct ieee80211_vif *vif,
1758 struct ieee80211_bss_conf *bss_conf,
1759 u32 changed)
1760{
1761 enum wl1271_cmd_ps_mode mode;
1762 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001763 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001764 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001765 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766 int ret;
1767
1768 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1769
1770 mutex_lock(&wl->mutex);
1771
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001772 if (unlikely(wl->state == WL1271_STATE_OFF))
1773 goto out;
1774
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775 ret = wl1271_ps_elp_wakeup(wl, false);
1776 if (ret < 0)
1777 goto out;
1778
Eliad Peller9ee82d52010-09-19 18:55:09 +02001779 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001780 (wl->bss_type == BSS_TYPE_IBSS)) {
1781 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1782 bss_conf->beacon_int);
1783
1784 wl->beacon_int = bss_conf->beacon_int;
1785 do_join = true;
1786 }
1787
Eliad Peller9ee82d52010-09-19 18:55:09 +02001788 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001789 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001790 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1791
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001792 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1793
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001794 if (beacon) {
1795 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001796
1797 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001798 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1799 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001800 beacon->len, 0,
1801 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001802
1803 if (ret < 0) {
1804 dev_kfree_skb(beacon);
1805 goto out_sleep;
1806 }
1807
1808 hdr = (struct ieee80211_hdr *) beacon->data;
1809 hdr->frame_control = cpu_to_le16(
1810 IEEE80211_FTYPE_MGMT |
1811 IEEE80211_STYPE_PROBE_RESP);
1812
1813 ret = wl1271_cmd_template_set(wl,
1814 CMD_TEMPL_PROBE_RESPONSE,
1815 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001816 beacon->len, 0,
1817 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001818 dev_kfree_skb(beacon);
1819 if (ret < 0)
1820 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001821
1822 /* Need to update the SSID (for filtering etc) */
1823 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001824 }
1825 }
1826
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001827 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1828 (wl->bss_type == BSS_TYPE_IBSS)) {
1829 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1830 bss_conf->enable_beacon ? "enabled" : "disabled");
1831
1832 if (bss_conf->enable_beacon)
1833 wl->set_bss_type = BSS_TYPE_IBSS;
1834 else
1835 wl->set_bss_type = BSS_TYPE_STA_BSS;
1836 do_join = true;
1837 }
1838
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001839 if (changed & BSS_CHANGED_CQM) {
1840 bool enable = false;
1841 if (bss_conf->cqm_rssi_thold)
1842 enable = true;
1843 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1844 bss_conf->cqm_rssi_thold,
1845 bss_conf->cqm_rssi_hyst);
1846 if (ret < 0)
1847 goto out;
1848 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1849 }
1850
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001851 if ((changed & BSS_CHANGED_BSSID) &&
1852 /*
1853 * Now we know the correct bssid, so we send a new join command
1854 * and enable the BSSID filter
1855 */
1856 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001857 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001858
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001859 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001860 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001861 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001862
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001863 ret = wl1271_build_qos_null_data(wl);
1864 if (ret < 0)
1865 goto out_sleep;
1866
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001867 /* filter out all packets not from this BSSID */
1868 wl1271_configure_filters(wl, 0);
1869
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001870 /* Need to update the BSSID (for filtering etc) */
1871 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001872 }
1873
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001874 if (changed & BSS_CHANGED_ASSOC) {
1875 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001876 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001878 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001879
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001880 wl->ps_poll_failures = 0;
1881
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001882 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001883 * use basic rates from AP, and determine lowest rate
1884 * to use with control frames.
1885 */
1886 rates = bss_conf->basic_rates;
1887 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1888 rates);
1889 wl->basic_rate = wl1271_min_rate_get(wl);
1890 ret = wl1271_acx_rate_policies(wl);
1891 if (ret < 0)
1892 goto out_sleep;
1893
1894 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001895 * with wl1271, we don't need to update the
1896 * beacon_int and dtim_period, because the firmware
1897 * updates it by itself when the first beacon is
1898 * received after a join.
1899 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001900 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1901 if (ret < 0)
1902 goto out_sleep;
1903
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001904 /*
1905 * The SSID is intentionally set to NULL here - the
1906 * firmware will set the probe request with a
1907 * broadcast SSID regardless of what we set in the
1908 * template.
1909 */
1910 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1911 NULL, 0, wl->band);
1912
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001913 /* enable the connection monitoring feature */
1914 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915 if (ret < 0)
1916 goto out_sleep;
1917
1918 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001919 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1920 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001922 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001923 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001924 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001925 if (ret < 0)
1926 goto out_sleep;
1927 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001928 } else {
1929 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001930 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001931 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001932 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001933
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001934 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001935 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001936
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001937 /* revert back to minimum rates for the current band */
1938 wl1271_set_band_rate(wl);
1939 wl->basic_rate = wl1271_min_rate_get(wl);
1940 ret = wl1271_acx_rate_policies(wl);
1941 if (ret < 0)
1942 goto out_sleep;
1943
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001944 /* disable connection monitor features */
1945 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001946
1947 /* Disable the keep-alive feature */
1948 ret = wl1271_acx_keep_alive_mode(wl, false);
1949
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001950 if (ret < 0)
1951 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 if (changed & BSS_CHANGED_ERP_SLOT) {
1957 if (bss_conf->use_short_slot)
1958 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1959 else
1960 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1961 if (ret < 0) {
1962 wl1271_warning("Set slot time failed %d", ret);
1963 goto out_sleep;
1964 }
1965 }
1966
1967 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1968 if (bss_conf->use_short_preamble)
1969 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1970 else
1971 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1972 }
1973
1974 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1975 if (bss_conf->use_cts_prot)
1976 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1977 else
1978 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1979 if (ret < 0) {
1980 wl1271_warning("Set ctsprotect failed %d", ret);
1981 goto out_sleep;
1982 }
1983 }
1984
Shahar Levi18357852010-10-13 16:09:41 +02001985 /*
1986 * Takes care of: New association with HT enable,
1987 * HT information change in beacon.
1988 */
1989 if (sta &&
1990 (changed & BSS_CHANGED_HT) &&
1991 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
1992 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
1993 if (ret < 0) {
1994 wl1271_warning("Set ht cap true failed %d", ret);
1995 goto out_sleep;
1996 }
1997 ret = wl1271_acx_set_ht_information(wl,
1998 bss_conf->ht_operation_mode);
1999 if (ret < 0) {
2000 wl1271_warning("Set ht information failed %d", ret);
2001 goto out_sleep;
2002 }
2003 }
2004 /*
2005 * Takes care of: New association without HT,
2006 * Disassociation.
2007 */
2008 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2009 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2010 if (ret < 0) {
2011 wl1271_warning("Set ht cap false failed %d", ret);
2012 goto out_sleep;
2013 }
2014 }
2015
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002016 if (changed & BSS_CHANGED_ARP_FILTER) {
2017 __be32 addr = bss_conf->arp_addr_list[0];
2018 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2019
2020 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
2021 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
2022 else
2023 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
2024
2025 if (ret < 0)
2026 goto out_sleep;
2027 }
2028
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002029 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002030 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002031 if (ret < 0) {
2032 wl1271_warning("cmd join failed %d", ret);
2033 goto out_sleep;
2034 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002035 }
2036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037out_sleep:
2038 wl1271_ps_elp_sleep(wl);
2039
2040out:
2041 mutex_unlock(&wl->mutex);
2042}
2043
Kalle Valoc6999d82010-02-18 13:25:41 +02002044static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2045 const struct ieee80211_tx_queue_params *params)
2046{
2047 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002048 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002049 int ret;
2050
2051 mutex_lock(&wl->mutex);
2052
2053 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2054
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002055 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2056 ret = -EAGAIN;
2057 goto out;
2058 }
2059
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002060 ret = wl1271_ps_elp_wakeup(wl, false);
2061 if (ret < 0)
2062 goto out;
2063
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002064 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002065 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2066 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002067 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002068 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002069 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002070
Kalle Valo4695dc92010-03-18 12:26:38 +02002071 if (params->uapsd)
2072 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2073 else
2074 ps_scheme = CONF_PS_SCHEME_LEGACY;
2075
Kalle Valoc6999d82010-02-18 13:25:41 +02002076 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2077 CONF_CHANNEL_TYPE_EDCF,
2078 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002079 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002080 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002081 goto out_sleep;
2082
2083out_sleep:
2084 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002085
2086out:
2087 mutex_unlock(&wl->mutex);
2088
2089 return ret;
2090}
2091
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002092static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2093{
2094
2095 struct wl1271 *wl = hw->priv;
2096 u64 mactime = ULLONG_MAX;
2097 int ret;
2098
2099 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2100
2101 mutex_lock(&wl->mutex);
2102
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002103 if (unlikely(wl->state == WL1271_STATE_OFF))
2104 goto out;
2105
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002106 ret = wl1271_ps_elp_wakeup(wl, false);
2107 if (ret < 0)
2108 goto out;
2109
2110 ret = wl1271_acx_tsf_info(wl, &mactime);
2111 if (ret < 0)
2112 goto out_sleep;
2113
2114out_sleep:
2115 wl1271_ps_elp_sleep(wl);
2116
2117out:
2118 mutex_unlock(&wl->mutex);
2119 return mactime;
2120}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121
John W. Linvilleece550d2010-07-28 16:41:06 -04002122static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2123 struct survey_info *survey)
2124{
2125 struct wl1271 *wl = hw->priv;
2126 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002127
John W. Linvilleece550d2010-07-28 16:41:06 -04002128 if (idx != 0)
2129 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002130
John W. Linvilleece550d2010-07-28 16:41:06 -04002131 survey->channel = conf->channel;
2132 survey->filled = SURVEY_INFO_NOISE_DBM;
2133 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002134
John W. Linvilleece550d2010-07-28 16:41:06 -04002135 return 0;
2136}
2137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138/* can't be const, mac80211 writes to this */
2139static struct ieee80211_rate wl1271_rates[] = {
2140 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002141 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2142 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002144 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2145 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2147 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002148 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2149 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2151 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002152 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2153 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2155 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002156 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2157 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002159 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2160 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002162 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2163 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002165 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2166 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002168 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2169 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002171 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2172 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002174 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2175 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002177 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2178 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179};
2180
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002181/*
2182 * Can't be const, mac80211 writes to this. The order of the channels here
2183 * is designed to improve scanning.
2184 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002186 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002187 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002188 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002189 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002190 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2191 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2192 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2193 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2194 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2195 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2196 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2197 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2198 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199};
2200
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002201/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002202static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002203 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002204 7, /* CONF_HW_RXTX_RATE_MCS7 */
2205 6, /* CONF_HW_RXTX_RATE_MCS6 */
2206 5, /* CONF_HW_RXTX_RATE_MCS5 */
2207 4, /* CONF_HW_RXTX_RATE_MCS4 */
2208 3, /* CONF_HW_RXTX_RATE_MCS3 */
2209 2, /* CONF_HW_RXTX_RATE_MCS2 */
2210 1, /* CONF_HW_RXTX_RATE_MCS1 */
2211 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002212
2213 11, /* CONF_HW_RXTX_RATE_54 */
2214 10, /* CONF_HW_RXTX_RATE_48 */
2215 9, /* CONF_HW_RXTX_RATE_36 */
2216 8, /* CONF_HW_RXTX_RATE_24 */
2217
2218 /* TI-specific rate */
2219 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2220
2221 7, /* CONF_HW_RXTX_RATE_18 */
2222 6, /* CONF_HW_RXTX_RATE_12 */
2223 3, /* CONF_HW_RXTX_RATE_11 */
2224 5, /* CONF_HW_RXTX_RATE_9 */
2225 4, /* CONF_HW_RXTX_RATE_6 */
2226 2, /* CONF_HW_RXTX_RATE_5_5 */
2227 1, /* CONF_HW_RXTX_RATE_2 */
2228 0 /* CONF_HW_RXTX_RATE_1 */
2229};
2230
Shahar Levie8b03a22010-10-13 16:09:39 +02002231/* 11n STA capabilities */
2232#define HW_RX_HIGHEST_RATE 72
2233
Shahar Levi18357852010-10-13 16:09:41 +02002234#ifdef CONFIG_WL1271_HT
Shahar Levie8b03a22010-10-13 16:09:39 +02002235#define WL1271_HT_CAP { \
2236 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2237 .ht_supported = true, \
2238 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2239 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2240 .mcs = { \
2241 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2242 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2243 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2244 }, \
2245}
Shahar Levi18357852010-10-13 16:09:41 +02002246#else
2247#define WL1271_HT_CAP { \
2248 .ht_supported = false, \
2249}
2250#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002251
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002252/* can't be const, mac80211 writes to this */
2253static struct ieee80211_supported_band wl1271_band_2ghz = {
2254 .channels = wl1271_channels,
2255 .n_channels = ARRAY_SIZE(wl1271_channels),
2256 .bitrates = wl1271_rates,
2257 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi18357852010-10-13 16:09:41 +02002258 .ht_cap = WL1271_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002259};
2260
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002261/* 5 GHz data rates for WL1273 */
2262static struct ieee80211_rate wl1271_rates_5ghz[] = {
2263 { .bitrate = 60,
2264 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2265 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2266 { .bitrate = 90,
2267 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2268 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2269 { .bitrate = 120,
2270 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2271 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2272 { .bitrate = 180,
2273 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2274 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2275 { .bitrate = 240,
2276 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2277 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2278 { .bitrate = 360,
2279 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2280 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2281 { .bitrate = 480,
2282 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2283 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2284 { .bitrate = 540,
2285 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2286 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2287};
2288
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002289/*
2290 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2291 * The order of the channels here is designed to improve scanning.
2292 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002293static struct ieee80211_channel wl1271_channels_5ghz[] = {
2294 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002295 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002296 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002297 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002298 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002299 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002300 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002301 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002302 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002303 { .hw_value = 184, .center_freq = 4920},
2304 { .hw_value = 189, .center_freq = 4945},
2305 { .hw_value = 9, .center_freq = 5045},
2306 { .hw_value = 36, .center_freq = 5180},
2307 { .hw_value = 46, .center_freq = 5230},
2308 { .hw_value = 64, .center_freq = 5320},
2309 { .hw_value = 116, .center_freq = 5580},
2310 { .hw_value = 136, .center_freq = 5680},
2311 { .hw_value = 192, .center_freq = 4960},
2312 { .hw_value = 11, .center_freq = 5055},
2313 { .hw_value = 38, .center_freq = 5190},
2314 { .hw_value = 48, .center_freq = 5240},
2315 { .hw_value = 100, .center_freq = 5500},
2316 { .hw_value = 120, .center_freq = 5600},
2317 { .hw_value = 140, .center_freq = 5700},
2318 { .hw_value = 185, .center_freq = 4925},
2319 { .hw_value = 196, .center_freq = 4980},
2320 { .hw_value = 12, .center_freq = 5060},
2321 { .hw_value = 40, .center_freq = 5200},
2322 { .hw_value = 52, .center_freq = 5260},
2323 { .hw_value = 104, .center_freq = 5520},
2324 { .hw_value = 124, .center_freq = 5620},
2325 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002326 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002327 { .hw_value = 187, .center_freq = 4935},
2328 { .hw_value = 7, .center_freq = 5035},
2329 { .hw_value = 16, .center_freq = 5080},
2330 { .hw_value = 42, .center_freq = 5210},
2331 { .hw_value = 56, .center_freq = 5280},
2332 { .hw_value = 108, .center_freq = 5540},
2333 { .hw_value = 128, .center_freq = 5640},
2334 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002335 { .hw_value = 165, .center_freq = 5825},
2336};
2337
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002338/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002339static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002340 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002341 7, /* CONF_HW_RXTX_RATE_MCS7 */
2342 6, /* CONF_HW_RXTX_RATE_MCS6 */
2343 5, /* CONF_HW_RXTX_RATE_MCS5 */
2344 4, /* CONF_HW_RXTX_RATE_MCS4 */
2345 3, /* CONF_HW_RXTX_RATE_MCS3 */
2346 2, /* CONF_HW_RXTX_RATE_MCS2 */
2347 1, /* CONF_HW_RXTX_RATE_MCS1 */
2348 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002349
2350 7, /* CONF_HW_RXTX_RATE_54 */
2351 6, /* CONF_HW_RXTX_RATE_48 */
2352 5, /* CONF_HW_RXTX_RATE_36 */
2353 4, /* CONF_HW_RXTX_RATE_24 */
2354
2355 /* TI-specific rate */
2356 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2357
2358 3, /* CONF_HW_RXTX_RATE_18 */
2359 2, /* CONF_HW_RXTX_RATE_12 */
2360 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2361 1, /* CONF_HW_RXTX_RATE_9 */
2362 0, /* CONF_HW_RXTX_RATE_6 */
2363 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2364 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2365 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2366};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002367
2368static struct ieee80211_supported_band wl1271_band_5ghz = {
2369 .channels = wl1271_channels_5ghz,
2370 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2371 .bitrates = wl1271_rates_5ghz,
2372 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi18357852010-10-13 16:09:41 +02002373 .ht_cap = WL1271_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002374};
2375
Tobias Klausera0ea9492010-05-20 10:38:11 +02002376static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002377 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2378 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2379};
2380
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002381static const struct ieee80211_ops wl1271_ops = {
2382 .start = wl1271_op_start,
2383 .stop = wl1271_op_stop,
2384 .add_interface = wl1271_op_add_interface,
2385 .remove_interface = wl1271_op_remove_interface,
2386 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002387 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 .configure_filter = wl1271_op_configure_filter,
2389 .tx = wl1271_op_tx,
2390 .set_key = wl1271_op_set_key,
2391 .hw_scan = wl1271_op_hw_scan,
2392 .bss_info_changed = wl1271_op_bss_info_changed,
2393 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002394 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002395 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002396 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002397 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398};
2399
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002400
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002401u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002402{
2403 u8 idx;
2404
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002405 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002406
2407 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2408 wl1271_error("Illegal RX rate from HW: %d", rate);
2409 return 0;
2410 }
2411
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002412 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002413 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2414 wl1271_error("Unsupported RX rate from HW: %d", rate);
2415 return 0;
2416 }
2417
2418 return idx;
2419}
2420
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002421static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2422 struct device_attribute *attr,
2423 char *buf)
2424{
2425 struct wl1271 *wl = dev_get_drvdata(dev);
2426 ssize_t len;
2427
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002428 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002429
2430 mutex_lock(&wl->mutex);
2431 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2432 wl->sg_enabled);
2433 mutex_unlock(&wl->mutex);
2434
2435 return len;
2436
2437}
2438
2439static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2440 struct device_attribute *attr,
2441 const char *buf, size_t count)
2442{
2443 struct wl1271 *wl = dev_get_drvdata(dev);
2444 unsigned long res;
2445 int ret;
2446
2447 ret = strict_strtoul(buf, 10, &res);
2448
2449 if (ret < 0) {
2450 wl1271_warning("incorrect value written to bt_coex_mode");
2451 return count;
2452 }
2453
2454 mutex_lock(&wl->mutex);
2455
2456 res = !!res;
2457
2458 if (res == wl->sg_enabled)
2459 goto out;
2460
2461 wl->sg_enabled = res;
2462
2463 if (wl->state == WL1271_STATE_OFF)
2464 goto out;
2465
2466 ret = wl1271_ps_elp_wakeup(wl, false);
2467 if (ret < 0)
2468 goto out;
2469
2470 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2471 wl1271_ps_elp_sleep(wl);
2472
2473 out:
2474 mutex_unlock(&wl->mutex);
2475 return count;
2476}
2477
2478static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2479 wl1271_sysfs_show_bt_coex_state,
2480 wl1271_sysfs_store_bt_coex_state);
2481
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002482static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2483 struct device_attribute *attr,
2484 char *buf)
2485{
2486 struct wl1271 *wl = dev_get_drvdata(dev);
2487 ssize_t len;
2488
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002489 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002490
2491 mutex_lock(&wl->mutex);
2492 if (wl->hw_pg_ver >= 0)
2493 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2494 else
2495 len = snprintf(buf, len, "n/a\n");
2496 mutex_unlock(&wl->mutex);
2497
2498 return len;
2499}
2500
2501static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2502 wl1271_sysfs_show_hw_pg_ver, NULL);
2503
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002504int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002505{
2506 int ret;
2507
2508 if (wl->mac80211_registered)
2509 return 0;
2510
2511 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2512
2513 ret = ieee80211_register_hw(wl->hw);
2514 if (ret < 0) {
2515 wl1271_error("unable to register mac80211 hw: %d", ret);
2516 return ret;
2517 }
2518
2519 wl->mac80211_registered = true;
2520
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002521 register_netdevice_notifier(&wl1271_dev_notifier);
2522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002523 wl1271_notice("loaded");
2524
2525 return 0;
2526}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002527EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002529void wl1271_unregister_hw(struct wl1271 *wl)
2530{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002531 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002532 ieee80211_unregister_hw(wl->hw);
2533 wl->mac80211_registered = false;
2534
2535}
2536EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2537
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002538int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002540 static const u32 cipher_suites[] = {
2541 WLAN_CIPHER_SUITE_WEP40,
2542 WLAN_CIPHER_SUITE_WEP104,
2543 WLAN_CIPHER_SUITE_TKIP,
2544 WLAN_CIPHER_SUITE_CCMP,
2545 WL1271_CIPHER_SUITE_GEM,
2546 };
2547
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002548 /* The tx descriptor buffer and the TKIP space. */
2549 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2550 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551
2552 /* unit us */
2553 /* FIXME: find a proper value */
2554 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002555 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
2557 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002558 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002559 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002560 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002561 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002562 IEEE80211_HW_CONNECTION_MONITOR |
2563 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002564
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002565 wl->hw->wiphy->cipher_suites = cipher_suites;
2566 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2567
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002568 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2569 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570 wl->hw->wiphy->max_scan_ssids = 1;
2571 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002572 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002573
Kalle Valo12bd8942010-03-18 12:26:33 +02002574 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002575 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002576
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002577 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578
2579 return 0;
2580}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002581EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002583#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002584
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002585struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002588 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002590 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002591 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592
2593 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2594 if (!hw) {
2595 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002596 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002597 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002598 }
2599
Julia Lawall929ebd32010-05-15 23:16:39 +02002600 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002601 if (!plat_dev) {
2602 wl1271_error("could not allocate platform_device");
2603 ret = -ENOMEM;
2604 goto err_plat_alloc;
2605 }
2606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002607 wl = hw->priv;
2608 memset(wl, 0, sizeof(*wl));
2609
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002610 INIT_LIST_HEAD(&wl->list);
2611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002612 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002613 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614
2615 skb_queue_head_init(&wl->tx_queue);
2616
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002617 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002618 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002619 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2620 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2621 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2622 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002624 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002625 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002626 wl->rx_counter = 0;
2627 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2628 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002629 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002631 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002632 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002633 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2634 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002635 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002636 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002637 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002638 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002639 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002641 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002642 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002643 wl->tx_frames[i] = NULL;
2644
2645 spin_lock_init(&wl->wl_lock);
2646
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647 wl->state = WL1271_STATE_OFF;
2648 mutex_init(&wl->mutex);
2649
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002650 /* Apply default driver configuration. */
2651 wl1271_conf_init(wl);
2652
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002653 wl1271_debugfs_init(wl);
2654
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002655 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2656 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2657 if (!wl->aggr_buf) {
2658 ret = -ENOMEM;
2659 goto err_hw;
2660 }
2661
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002662 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002663 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002664 if (ret) {
2665 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002666 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002667 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002668 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002669
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002670 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002671 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002672 if (ret < 0) {
2673 wl1271_error("failed to create sysfs file bt_coex_state");
2674 goto err_platform;
2675 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002676
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002677 /* Create sysfs file to get HW PG version */
2678 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2679 if (ret < 0) {
2680 wl1271_error("failed to create sysfs file hw_pg_ver");
2681 goto err_bt_coex_state;
2682 }
2683
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002684 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002685
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002686err_bt_coex_state:
2687 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2688
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002689err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002690 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002691
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002692err_aggr:
2693 free_pages((unsigned long)wl->aggr_buf, order);
2694
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002695err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002696 wl1271_debugfs_exit(wl);
2697 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002698
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002699err_plat_alloc:
2700 ieee80211_free_hw(hw);
2701
2702err_hw_alloc:
2703
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002704 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002705}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002706EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002707
2708int wl1271_free_hw(struct wl1271 *wl)
2709{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002710 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002711 free_pages((unsigned long)wl->aggr_buf,
2712 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002713 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002714
2715 wl1271_debugfs_exit(wl);
2716
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002717 vfree(wl->fw);
2718 wl->fw = NULL;
2719 kfree(wl->nvs);
2720 wl->nvs = NULL;
2721
2722 kfree(wl->fw_status);
2723 kfree(wl->tx_res_if);
2724
2725 ieee80211_free_hw(wl->hw);
2726
2727 return 0;
2728}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002729EXPORT_SYMBOL_GPL(wl1271_free_hw);
2730
2731MODULE_LICENSE("GPL");
2732MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2733MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");