blob: 07243282e50a2ee08c454a488261f57eadafdf9f [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200156 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300157 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200158 [CONF_TX_AC_BE] = {
159 .queue_id = CONF_TX_AC_BE,
160 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200166 [CONF_TX_AC_BK] = {
167 .queue_id = CONF_TX_AC_BK,
168 .channel_type = CONF_CHANNEL_TYPE_EDCF,
169 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_VI] = {
175 .queue_id = CONF_TX_AC_VI,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
177 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_VO] = {
183 .queue_id = CONF_TX_AC_VO,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 },
191 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300193 .tx_compl_threshold = 4,
194 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
195 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 },
197 .conn = {
198 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300199 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
201 .bcn_filt_ie_count = 1,
202 .bcn_filt_ie = {
203 [0] = {
204 .ie = WLAN_EID_CHANNEL_SWITCH,
205 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
206 }
207 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .bss_lose_timeout = 100,
210 .beacon_rx_timeout = 10000,
211 .broadcast_timeout = 20000,
212 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300213 .ps_poll_threshold = 10,
214 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300215 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200216 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200217 .psm_entry_retries = 5,
218 .psm_entry_nullfunc_retries = 3,
219 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300220 .keep_alive_interval = 55000,
221 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200223 .itrim = {
224 .enable = false,
225 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200226 },
227 .pm_config = {
228 .host_clk_settling_time = 5000,
229 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300230 },
231 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300232 .trigger_pacing = 1,
233 .avg_weight_rssi_beacon = 20,
234 .avg_weight_rssi_data = 10,
235 .avg_weight_snr_beacon = 20,
236 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200237 },
238 .scan = {
239 .min_dwell_time_active = 7500,
240 .max_dwell_time_active = 30000,
241 .min_dwell_time_passive = 30000,
242 .max_dwell_time_passive = 60000,
243 .num_probe_reqs = 2,
244 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200245 .rf = {
246 .tx_per_channel_power_compensation_2 = {
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 },
249 .tx_per_channel_power_compensation_5 = {
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 },
254 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255};
256
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200257static void __wl1271_op_remove_interface(struct wl1271 *wl);
258
259
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200260static void wl1271_device_release(struct device *dev)
261{
262
263}
264
265static struct platform_device wl1271_device = {
266 .name = "wl1271",
267 .id = -1,
268
269 /* device model insists to have a release function */
270 .dev = {
271 .release = wl1271_device_release,
272 },
273};
274
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300275static LIST_HEAD(wl_list);
276
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300277static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
278 void *arg)
279{
280 struct net_device *dev = arg;
281 struct wireless_dev *wdev;
282 struct wiphy *wiphy;
283 struct ieee80211_hw *hw;
284 struct wl1271 *wl;
285 struct wl1271 *wl_temp;
286 int ret = 0;
287
288 /* Check that this notification is for us. */
289 if (what != NETDEV_CHANGE)
290 return NOTIFY_DONE;
291
292 wdev = dev->ieee80211_ptr;
293 if (wdev == NULL)
294 return NOTIFY_DONE;
295
296 wiphy = wdev->wiphy;
297 if (wiphy == NULL)
298 return NOTIFY_DONE;
299
300 hw = wiphy_priv(wiphy);
301 if (hw == NULL)
302 return NOTIFY_DONE;
303
304 wl_temp = hw->priv;
305 list_for_each_entry(wl, &wl_list, list) {
306 if (wl == wl_temp)
307 break;
308 }
309 if (wl != wl_temp)
310 return NOTIFY_DONE;
311
312 mutex_lock(&wl->mutex);
313
314 if (wl->state == WL1271_STATE_OFF)
315 goto out;
316
317 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
318 goto out;
319
320 ret = wl1271_ps_elp_wakeup(wl, false);
321 if (ret < 0)
322 goto out;
323
324 if ((dev->operstate == IF_OPER_UP) &&
325 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
326 wl1271_cmd_set_sta_state(wl);
327 wl1271_info("Association completed.");
328 }
329
330 wl1271_ps_elp_sleep(wl);
331
332out:
333 mutex_unlock(&wl->mutex);
334
335 return NOTIFY_OK;
336}
337
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100338static int wl1271_reg_notify(struct wiphy *wiphy,
339 struct regulatory_request *request) {
340 struct ieee80211_supported_band *band;
341 struct ieee80211_channel *ch;
342 int i;
343
344 band = wiphy->bands[IEEE80211_BAND_5GHZ];
345 for (i = 0; i < band->n_channels; i++) {
346 ch = &band->channels[i];
347 if (ch->flags & IEEE80211_CHAN_DISABLED)
348 continue;
349
350 if (ch->flags & IEEE80211_CHAN_RADAR)
351 ch->flags |= IEEE80211_CHAN_NO_IBSS |
352 IEEE80211_CHAN_PASSIVE_SCAN;
353
354 }
355
356 return 0;
357}
358
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300359static void wl1271_conf_init(struct wl1271 *wl)
360{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300361
362 /*
363 * This function applies the default configuration to the driver. This
364 * function is invoked upon driver load (spi probe.)
365 *
366 * The configuration is stored in a run-time structure in order to
367 * facilitate for run-time adjustment of any of the parameters. Making
368 * changes to the configuration structure will apply the new values on
369 * the next interface up (wl1271_op_start.)
370 */
371
372 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300373 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300374}
375
376
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300377static int wl1271_plt_init(struct wl1271 *wl)
378{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200379 struct conf_tx_ac_category *conf_ac;
380 struct conf_tx_tid *conf_tid;
381 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200383 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200384 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200385 return ret;
386
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200387 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200388 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200389 return ret;
390
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200391 ret = wl1271_cmd_ext_radio_parms(wl);
392 if (ret < 0)
393 return ret;
394
Luciano Coelho12419cc2010-02-18 13:25:44 +0200395 ret = wl1271_init_templates_config(wl);
396 if (ret < 0)
397 return ret;
398
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399 ret = wl1271_acx_init_mem_config(wl);
400 if (ret < 0)
401 return ret;
402
Luciano Coelho12419cc2010-02-18 13:25:44 +0200403 /* PHY layer config */
404 ret = wl1271_init_phy_config(wl);
405 if (ret < 0)
406 goto out_free_memmap;
407
408 ret = wl1271_acx_dco_itrim_params(wl);
409 if (ret < 0)
410 goto out_free_memmap;
411
412 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200413 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200414 if (ret < 0)
415 goto out_free_memmap;
416
417 /* Bluetooth WLAN coexistence */
418 ret = wl1271_init_pta(wl);
419 if (ret < 0)
420 goto out_free_memmap;
421
422 /* Energy detection */
423 ret = wl1271_init_energy_detection(wl);
424 if (ret < 0)
425 goto out_free_memmap;
426
427 /* Default fragmentation threshold */
428 ret = wl1271_acx_frag_threshold(wl);
429 if (ret < 0)
430 goto out_free_memmap;
431
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200432 /* Default TID/AC configuration */
433 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200434 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200435 conf_ac = &wl->conf.tx.ac_conf[i];
436 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
437 conf_ac->cw_max, conf_ac->aifsn,
438 conf_ac->tx_op_limit);
439 if (ret < 0)
440 goto out_free_memmap;
441
Luciano Coelho12419cc2010-02-18 13:25:44 +0200442 conf_tid = &wl->conf.tx.tid_conf[i];
443 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
444 conf_tid->channel_type,
445 conf_tid->tsid,
446 conf_tid->ps_scheme,
447 conf_tid->ack_policy,
448 conf_tid->apsd_conf[0],
449 conf_tid->apsd_conf[1]);
450 if (ret < 0)
451 goto out_free_memmap;
452 }
453
Luciano Coelho12419cc2010-02-18 13:25:44 +0200454 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200455 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200457 goto out_free_memmap;
458
459 /* Configure for CAM power saving (ie. always active) */
460 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
461 if (ret < 0)
462 goto out_free_memmap;
463
464 /* configure PM */
465 ret = wl1271_acx_pm_config(wl);
466 if (ret < 0)
467 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
469 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200470
471 out_free_memmap:
472 kfree(wl->target_mem_map);
473 wl->target_mem_map = NULL;
474
475 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476}
477
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300478static void wl1271_fw_status(struct wl1271 *wl,
479 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200481 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482 u32 total = 0;
483 int i;
484
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200485 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
487 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
488 "drv_rx_counter = %d, tx_results_counter = %d)",
489 status->intr,
490 status->fw_rx_counter,
491 status->drv_rx_counter,
492 status->tx_results_counter);
493
494 /* update number of available TX blocks */
495 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300496 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
497 wl->tx_blocks_freed[i];
498
499 wl->tx_blocks_freed[i] =
500 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300501 wl->tx_blocks_available += cnt;
502 total += cnt;
503 }
504
Ido Yariva5225502010-10-12 14:49:10 +0200505 /* if more blocks are available now, tx work can be scheduled */
506 if (total)
507 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300508
509 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200510 getnstimeofday(&ts);
511 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
512 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513}
514
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200515#define WL1271_IRQ_MAX_LOOPS 10
516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300517static void wl1271_irq_work(struct work_struct *work)
518{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300520 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200521 int loopcount = WL1271_IRQ_MAX_LOOPS;
522 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523 struct wl1271 *wl =
524 container_of(work, struct wl1271, irq_work);
525
526 mutex_lock(&wl->mutex);
527
528 wl1271_debug(DEBUG_IRQ, "IRQ work");
529
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200530 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300531 goto out;
532
533 ret = wl1271_ps_elp_wakeup(wl, true);
534 if (ret < 0)
535 goto out;
536
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200537 spin_lock_irqsave(&wl->wl_lock, flags);
538 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
539 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
540 spin_unlock_irqrestore(&wl->wl_lock, flags);
541 loopcount--;
542
543 wl1271_fw_status(wl, wl->fw_status);
544 intr = le32_to_cpu(wl->fw_status->intr);
545 if (!intr) {
546 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200547 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200548 continue;
549 }
550
551 intr &= WL1271_INTR_MASK;
552
Eliad Pellerccc83b02010-10-27 14:09:57 +0200553 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
554 wl1271_error("watchdog interrupt received! "
555 "starting recovery.");
556 ieee80211_queue_work(wl->hw, &wl->recovery_work);
557
558 /* restarting the chip. ignore any other interrupt. */
559 goto out;
560 }
561
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200562 if (intr & WL1271_ACX_INTR_DATA) {
563 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
564
565 /* check for tx results */
566 if (wl->fw_status->tx_results_counter !=
567 (wl->tx_results_count & 0xff))
568 wl1271_tx_complete(wl);
569
Ido Yariva5225502010-10-12 14:49:10 +0200570 /* Check if any tx blocks were freed */
571 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
572 !skb_queue_empty(&wl->tx_queue)) {
573 /*
574 * In order to avoid starvation of the TX path,
575 * call the work function directly.
576 */
577 wl1271_tx_work_locked(wl);
578 }
579
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200580 wl1271_rx(wl, wl->fw_status);
581 }
582
583 if (intr & WL1271_ACX_INTR_EVENT_A) {
584 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
585 wl1271_event_handle(wl, 0);
586 }
587
588 if (intr & WL1271_ACX_INTR_EVENT_B) {
589 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
590 wl1271_event_handle(wl, 1);
591 }
592
593 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
594 wl1271_debug(DEBUG_IRQ,
595 "WL1271_ACX_INTR_INIT_COMPLETE");
596
597 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
598 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
599
600 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601 }
602
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200603 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
604 ieee80211_queue_work(wl->hw, &wl->irq_work);
605 else
606 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
607 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609 wl1271_ps_elp_sleep(wl);
610
611out:
612 mutex_unlock(&wl->mutex);
613}
614
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300615static int wl1271_fetch_firmware(struct wl1271 *wl)
616{
617 const struct firmware *fw;
618 int ret;
619
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200620 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621
622 if (ret < 0) {
623 wl1271_error("could not get firmware: %d", ret);
624 return ret;
625 }
626
627 if (fw->size % 4) {
628 wl1271_error("firmware size is not multiple of 32 bits: %zu",
629 fw->size);
630 ret = -EILSEQ;
631 goto out;
632 }
633
634 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300635 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 if (!wl->fw) {
638 wl1271_error("could not allocate memory for the firmware");
639 ret = -ENOMEM;
640 goto out;
641 }
642
643 memcpy(wl->fw, fw->data, wl->fw_len);
644
645 ret = 0;
646
647out:
648 release_firmware(fw);
649
650 return ret;
651}
652
653static int wl1271_fetch_nvs(struct wl1271 *wl)
654{
655 const struct firmware *fw;
656 int ret;
657
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200658 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659
660 if (ret < 0) {
661 wl1271_error("could not get nvs file: %d", ret);
662 return ret;
663 }
664
Julia Lawall929ebd32010-05-15 23:16:39 +0200665 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300666
667 if (!wl->nvs) {
668 wl1271_error("could not allocate memory for the nvs file");
669 ret = -ENOMEM;
670 goto out;
671 }
672
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200673 wl->nvs_len = fw->size;
674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675out:
676 release_firmware(fw);
677
678 return ret;
679}
680
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200681static void wl1271_recovery_work(struct work_struct *work)
682{
683 struct wl1271 *wl =
684 container_of(work, struct wl1271, recovery_work);
685
686 mutex_lock(&wl->mutex);
687
688 if (wl->state != WL1271_STATE_ON)
689 goto out;
690
691 wl1271_info("Hardware recovery in progress.");
692
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200693 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
694 ieee80211_connection_loss(wl->vif);
695
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200696 /* reboot the chipset */
697 __wl1271_op_remove_interface(wl);
698 ieee80211_restart_hw(wl->hw);
699
700out:
701 mutex_unlock(&wl->mutex);
702}
703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704static void wl1271_fw_wakeup(struct wl1271 *wl)
705{
706 u32 elp_reg;
707
708 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300709 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710}
711
712static int wl1271_setup(struct wl1271 *wl)
713{
714 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
715 if (!wl->fw_status)
716 return -ENOMEM;
717
718 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
719 if (!wl->tx_res_if) {
720 kfree(wl->fw_status);
721 return -ENOMEM;
722 }
723
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 return 0;
725}
726
727static int wl1271_chip_wakeup(struct wl1271 *wl)
728{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300729 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730 int ret = 0;
731
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200732 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200733 ret = wl1271_power_on(wl);
734 if (ret < 0)
735 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200737 wl1271_io_reset(wl);
738 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739
740 /* We don't need a real memory partition here, because we only want
741 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300742 memset(&partition, 0, sizeof(partition));
743 partition.reg.start = REGISTERS_BASE;
744 partition.reg.size = REGISTERS_DOWN_SIZE;
745 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746
747 /* ELP module wake up */
748 wl1271_fw_wakeup(wl);
749
750 /* whal_FwCtrl_BootSm() */
751
752 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200753 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754
755 /* 1. check if chip id is valid */
756
757 switch (wl->chip.id) {
758 case CHIP_ID_1271_PG10:
759 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
760 wl->chip.id);
761
762 ret = wl1271_setup(wl);
763 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200764 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765 break;
766 case CHIP_ID_1271_PG20:
767 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
768 wl->chip.id);
769
770 ret = wl1271_setup(wl);
771 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200772 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773 break;
774 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200775 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200777 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 }
779
780 if (wl->fw == NULL) {
781 ret = wl1271_fetch_firmware(wl);
782 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200783 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784 }
785
786 /* No NVS from netlink, try to get it from the filesystem */
787 if (wl->nvs == NULL) {
788 ret = wl1271_fetch_nvs(wl);
789 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200790 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 }
792
793out:
794 return ret;
795}
796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797int wl1271_plt_start(struct wl1271 *wl)
798{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200799 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800 int ret;
801
802 mutex_lock(&wl->mutex);
803
804 wl1271_notice("power up");
805
806 if (wl->state != WL1271_STATE_OFF) {
807 wl1271_error("cannot go into PLT state because not "
808 "in off state: %d", wl->state);
809 ret = -EBUSY;
810 goto out;
811 }
812
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200813 while (retries) {
814 retries--;
815 ret = wl1271_chip_wakeup(wl);
816 if (ret < 0)
817 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200819 ret = wl1271_boot(wl);
820 if (ret < 0)
821 goto power_off;
822
823 ret = wl1271_plt_init(wl);
824 if (ret < 0)
825 goto irq_disable;
826
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200827 wl->state = WL1271_STATE_PLT;
828 wl1271_notice("firmware booted in PLT mode (%s)",
829 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830 goto out;
831
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200832irq_disable:
833 wl1271_disable_interrupts(wl);
834 mutex_unlock(&wl->mutex);
835 /* Unlocking the mutex in the middle of handling is
836 inherently unsafe. In this case we deem it safe to do,
837 because we need to let any possibly pending IRQ out of
838 the system (and while we are WL1271_STATE_OFF the IRQ
839 work function will not do anything.) Also, any other
840 possible concurrent operations will fail due to the
841 current state, hence the wl1271 struct should be safe. */
842 cancel_work_sync(&wl->irq_work);
843 mutex_lock(&wl->mutex);
844power_off:
845 wl1271_power_off(wl);
846 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200848 wl1271_error("firmware boot in PLT mode failed despite %d retries",
849 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300850out:
851 mutex_unlock(&wl->mutex);
852
853 return ret;
854}
855
856int wl1271_plt_stop(struct wl1271 *wl)
857{
858 int ret = 0;
859
860 mutex_lock(&wl->mutex);
861
862 wl1271_notice("power down");
863
864 if (wl->state != WL1271_STATE_PLT) {
865 wl1271_error("cannot power down because not in PLT "
866 "state: %d", wl->state);
867 ret = -EBUSY;
868 goto out;
869 }
870
871 wl1271_disable_interrupts(wl);
872 wl1271_power_off(wl);
873
874 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300875 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876
877out:
878 mutex_unlock(&wl->mutex);
879
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200880 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200881 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200882
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883 return ret;
884}
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
887{
888 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200889 struct ieee80211_conf *conf = &hw->conf;
890 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
891 struct ieee80211_sta *sta = txinfo->control.sta;
892 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893
Shahar Levi18357852010-10-13 16:09:41 +0200894 /*
895 * peek into the rates configured in the STA entry.
896 * The rates set after connection stage, The first block only BG sets:
897 * the compare is for bit 0-16 of sta_rate_set. The second block add
898 * HT rates in case of HT supported.
899 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200900 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200901 if (sta &&
902 (sta->supp_rates[conf->channel->band] !=
903 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200904 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
905 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
906 }
Shahar Levi18357852010-10-13 16:09:41 +0200907
Shahar Levi00d20102010-11-08 11:20:10 +0000908#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200909 if (sta &&
910 sta->ht_cap.ht_supported &&
911 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
912 sta->ht_cap.mcs.rx_mask[0])) {
913 /* Clean MCS bits before setting them */
914 wl->sta_rate_set &= HW_BG_RATES_MASK;
915 wl->sta_rate_set |=
916 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
917 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
918 }
919#endif
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200920 spin_unlock_irqrestore(&wl->wl_lock, flags);
921
922 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923 skb_queue_tail(&wl->tx_queue, skb);
924
925 /*
926 * The chip specific setup must run before the first TX packet -
927 * before that, the tx_work will not be initialized!
928 */
929
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
931 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
933 /*
934 * The workqueue is slow to process the tx_queue and we need stop
935 * the queue here, otherwise the queue will get too long.
936 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200937 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
938 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200940 spin_lock_irqsave(&wl->wl_lock, flags);
941 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200942 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200943 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 }
945
946 return NETDEV_TX_OK;
947}
948
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300949static struct notifier_block wl1271_dev_notifier = {
950 .notifier_call = wl1271_dev_notify,
951};
952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953static int wl1271_op_start(struct ieee80211_hw *hw)
954{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200955 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
956
957 /*
958 * We have to delay the booting of the hardware because
959 * we need to know the local MAC address before downloading and
960 * initializing the firmware. The MAC address cannot be changed
961 * after boot, and without the proper MAC address, the firmware
962 * will not function properly.
963 *
964 * The MAC address is first known when the corresponding interface
965 * is added. That is where we will initialize the hardware.
966 */
967
968 return 0;
969}
970
971static void wl1271_op_stop(struct ieee80211_hw *hw)
972{
973 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
974}
975
976static int wl1271_op_add_interface(struct ieee80211_hw *hw,
977 struct ieee80211_vif *vif)
978{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400980 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +0200983 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200985 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
986 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
988 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200989 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +0200990 wl1271_debug(DEBUG_MAC80211,
991 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200992 ret = -EBUSY;
993 goto out;
994 }
995
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200996 switch (vif->type) {
997 case NL80211_IFTYPE_STATION:
998 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200999 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001000 break;
1001 case NL80211_IFTYPE_ADHOC:
1002 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001003 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001004 break;
1005 default:
1006 ret = -EOPNOTSUPP;
1007 goto out;
1008 }
1009
1010 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
1012 if (wl->state != WL1271_STATE_OFF) {
1013 wl1271_error("cannot start because not in off state: %d",
1014 wl->state);
1015 ret = -EBUSY;
1016 goto out;
1017 }
1018
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001019 while (retries) {
1020 retries--;
1021 ret = wl1271_chip_wakeup(wl);
1022 if (ret < 0)
1023 goto power_off;
1024
1025 ret = wl1271_boot(wl);
1026 if (ret < 0)
1027 goto power_off;
1028
1029 ret = wl1271_hw_init(wl);
1030 if (ret < 0)
1031 goto irq_disable;
1032
Eliad Peller71125ab2010-10-28 21:46:43 +02001033 booted = true;
1034 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001036irq_disable:
1037 wl1271_disable_interrupts(wl);
1038 mutex_unlock(&wl->mutex);
1039 /* Unlocking the mutex in the middle of handling is
1040 inherently unsafe. In this case we deem it safe to do,
1041 because we need to let any possibly pending IRQ out of
1042 the system (and while we are WL1271_STATE_OFF the IRQ
1043 work function will not do anything.) Also, any other
1044 possible concurrent operations will fail due to the
1045 current state, hence the wl1271 struct should be safe. */
1046 cancel_work_sync(&wl->irq_work);
1047 mutex_lock(&wl->mutex);
1048power_off:
1049 wl1271_power_off(wl);
1050 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051
Eliad Peller71125ab2010-10-28 21:46:43 +02001052 if (!booted) {
1053 wl1271_error("firmware boot failed despite %d retries",
1054 WL1271_BOOT_RETRIES);
1055 goto out;
1056 }
1057
1058 wl->vif = vif;
1059 wl->state = WL1271_STATE_ON;
1060 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1061
1062 /* update hw/fw version info in wiphy struct */
1063 wiphy->hw_version = wl->chip.id;
1064 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1065 sizeof(wiphy->fw_version));
1066
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001067out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 mutex_unlock(&wl->mutex);
1069
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001070 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001071 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073 return ret;
1074}
1075
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001076static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 int i;
1079
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001080 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001082 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001084 list_del(&wl->list);
1085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 WARN_ON(wl->state != WL1271_STATE_ON);
1087
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001088 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001089 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001090 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001091
Luciano Coelho08688d62010-07-08 17:50:07 +03001092 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001093 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1094 kfree(wl->scan.scanned_ch);
1095 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001096 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001097 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098 }
1099
1100 wl->state = WL1271_STATE_OFF;
1101
1102 wl1271_disable_interrupts(wl);
1103
1104 mutex_unlock(&wl->mutex);
1105
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001106 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 cancel_work_sync(&wl->irq_work);
1108 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001109 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001110 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 mutex_lock(&wl->mutex);
1113
1114 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001115 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116 wl1271_power_off(wl);
1117
1118 memset(wl->bssid, 0, ETH_ALEN);
1119 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1120 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001122 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001123 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124
1125 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001126 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1128 wl->tx_blocks_available = 0;
1129 wl->tx_results_count = 0;
1130 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001131 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001132 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133 wl->time_offset = 0;
1134 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001135 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1136 wl->sta_rate_set = 0;
1137 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001138 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001139 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001140
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 for (i = 0; i < NUM_TX_QUEUES; i++)
1142 wl->tx_blocks_freed[i] = 0;
1143
1144 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001145
1146 kfree(wl->fw_status);
1147 wl->fw_status = NULL;
1148 kfree(wl->tx_res_if);
1149 wl->tx_res_if = NULL;
1150 kfree(wl->target_mem_map);
1151 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001152}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001153
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001154static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1155 struct ieee80211_vif *vif)
1156{
1157 struct wl1271 *wl = hw->priv;
1158
1159 mutex_lock(&wl->mutex);
1160 WARN_ON(wl->vif != vif);
1161 __wl1271_op_remove_interface(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001163
1164 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001165}
1166
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001167static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1168{
1169 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1170 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1171
1172 /* combine requested filters with current filter config */
1173 filters = wl->filters | filters;
1174
1175 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1176
1177 if (filters & FIF_PROMISC_IN_BSS) {
1178 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1179 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1180 wl->rx_config |= CFG_BSSID_FILTER_EN;
1181 }
1182 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1183 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1184 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1185 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1186 }
1187 if (filters & FIF_OTHER_BSS) {
1188 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1189 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1190 }
1191 if (filters & FIF_CONTROL) {
1192 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1193 wl->rx_filter |= CFG_RX_CTL_EN;
1194 }
1195 if (filters & FIF_FCSFAIL) {
1196 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1197 wl->rx_filter |= CFG_RX_FCS_ERROR;
1198 }
1199}
1200
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001201static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001202{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001203 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001204 /* we need to use a dummy BSSID for now */
1205 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1206 0xad, 0xbe, 0xef };
1207
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1209
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001210 /* pass through frames from all BSS */
1211 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1212
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001213 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001214 if (ret < 0)
1215 goto out;
1216
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001217 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001218
1219out:
1220 return ret;
1221}
1222
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001223static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001224{
1225 int ret;
1226
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001227 /*
1228 * One of the side effects of the JOIN command is that is clears
1229 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1230 * to a WPA/WPA2 access point will therefore kill the data-path.
1231 * Currently there is no supported scenario for JOIN during
1232 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1233 * must be handled somehow.
1234 *
1235 */
1236 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1237 wl1271_info("JOIN while associated.");
1238
1239 if (set_assoc)
1240 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1241
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001242 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1243 if (ret < 0)
1244 goto out;
1245
1246 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1247
1248 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1249 goto out;
1250
1251 /*
1252 * The join command disable the keep-alive mode, shut down its process,
1253 * and also clear the template config, so we need to reset it all after
1254 * the join. The acx_aid starts the keep-alive process, and the order
1255 * of the commands below is relevant.
1256 */
1257 ret = wl1271_acx_keep_alive_mode(wl, true);
1258 if (ret < 0)
1259 goto out;
1260
1261 ret = wl1271_acx_aid(wl, wl->aid);
1262 if (ret < 0)
1263 goto out;
1264
1265 ret = wl1271_cmd_build_klv_null_data(wl);
1266 if (ret < 0)
1267 goto out;
1268
1269 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1270 ACX_KEEP_ALIVE_TPL_VALID);
1271 if (ret < 0)
1272 goto out;
1273
1274out:
1275 return ret;
1276}
1277
1278static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001279{
1280 int ret;
1281
1282 /* to stop listening to a channel, we disconnect */
1283 ret = wl1271_cmd_disconnect(wl);
1284 if (ret < 0)
1285 goto out;
1286
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001287 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001288 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001289
1290 /* stop filterting packets based on bssid */
1291 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001292
1293out:
1294 return ret;
1295}
1296
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001297static void wl1271_set_band_rate(struct wl1271 *wl)
1298{
1299 if (wl->band == IEEE80211_BAND_2GHZ)
1300 wl->basic_rate_set = wl->conf.tx.basic_rate;
1301 else
1302 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1303}
1304
1305static u32 wl1271_min_rate_get(struct wl1271 *wl)
1306{
1307 int i;
1308 u32 rate = 0;
1309
1310 if (!wl->basic_rate_set) {
1311 WARN_ON(1);
1312 wl->basic_rate_set = wl->conf.tx.basic_rate;
1313 }
1314
1315 for (i = 0; !rate; i++) {
1316 if ((wl->basic_rate_set >> i) & 0x1)
1317 rate = 1 << i;
1318 }
1319
1320 return rate;
1321}
1322
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001323static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1324{
1325 int ret;
1326
1327 if (idle) {
1328 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1329 ret = wl1271_unjoin(wl);
1330 if (ret < 0)
1331 goto out;
1332 }
1333 wl->rate_set = wl1271_min_rate_get(wl);
1334 wl->sta_rate_set = 0;
1335 ret = wl1271_acx_rate_policies(wl);
1336 if (ret < 0)
1337 goto out;
1338 ret = wl1271_acx_keep_alive_config(
1339 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1340 ACX_KEEP_ALIVE_TPL_INVALID);
1341 if (ret < 0)
1342 goto out;
1343 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1344 } else {
1345 /* increment the session counter */
1346 wl->session_counter++;
1347 if (wl->session_counter >= SESSION_COUNTER_MAX)
1348 wl->session_counter = 0;
1349 ret = wl1271_dummy_join(wl);
1350 if (ret < 0)
1351 goto out;
1352 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1353 }
1354
1355out:
1356 return ret;
1357}
1358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1360{
1361 struct wl1271 *wl = hw->priv;
1362 struct ieee80211_conf *conf = &hw->conf;
1363 int channel, ret = 0;
1364
1365 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1366
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001367 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 channel,
1369 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001370 conf->power_level,
1371 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001373 /*
1374 * mac80211 will go to idle nearly immediately after transmitting some
1375 * frames, such as the deauth. To make sure those frames reach the air,
1376 * wait here until the TX queue is fully flushed.
1377 */
1378 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1379 (conf->flags & IEEE80211_CONF_IDLE))
1380 wl1271_tx_flush(wl);
1381
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 mutex_lock(&wl->mutex);
1383
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001384 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1385 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001386 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001387 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 ret = wl1271_ps_elp_wakeup(wl, false);
1390 if (ret < 0)
1391 goto out;
1392
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001393 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001394 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1395 ((wl->band != conf->channel->band) ||
1396 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001397 wl->band = conf->channel->band;
1398 wl->channel = channel;
1399
1400 /*
1401 * FIXME: the mac80211 should really provide a fixed rate
1402 * to use here. for now, just use the smallest possible rate
1403 * for the band as a fixed rate for association frames and
1404 * other control messages.
1405 */
1406 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1407 wl1271_set_band_rate(wl);
1408
1409 wl->basic_rate = wl1271_min_rate_get(wl);
1410 ret = wl1271_acx_rate_policies(wl);
1411 if (ret < 0)
1412 wl1271_warning("rate policy for update channel "
1413 "failed %d", ret);
1414
1415 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001416 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001417 if (ret < 0)
1418 wl1271_warning("cmd join to update channel "
1419 "failed %d", ret);
1420 }
1421 }
1422
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001423 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001424 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1425 if (ret < 0)
1426 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427 }
1428
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001429 /*
1430 * if mac80211 changes the PSM mode, make sure the mode is not
1431 * incorrectly changed after the pspoll failure active window.
1432 */
1433 if (changed & IEEE80211_CONF_CHANGE_PS)
1434 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1435
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001436 if (conf->flags & IEEE80211_CONF_PS &&
1437 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1438 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439
1440 /*
1441 * We enter PSM only if we're already associated.
1442 * If we're not, we'll enter it when joining an SSID,
1443 * through the bss_info_changed() hook.
1444 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001445 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001446 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001447 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001448 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001449 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001451 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001452 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001454 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001456 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001457 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001458 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459 }
1460
1461 if (conf->power_level != wl->power_level) {
1462 ret = wl1271_acx_tx_power(wl, conf->power_level);
1463 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001464 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465
1466 wl->power_level = conf->power_level;
1467 }
1468
1469out_sleep:
1470 wl1271_ps_elp_sleep(wl);
1471
1472out:
1473 mutex_unlock(&wl->mutex);
1474
1475 return ret;
1476}
1477
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001478struct wl1271_filter_params {
1479 bool enabled;
1480 int mc_list_length;
1481 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1482};
1483
Jiri Pirko22bedad2010-04-01 21:22:57 +00001484static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1485 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001486{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001487 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001488 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001489 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001490
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001491 if (unlikely(wl->state == WL1271_STATE_OFF))
1492 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001493
Juuso Oikarinen74441132009-10-13 12:47:53 +03001494 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001495 if (!fp) {
1496 wl1271_error("Out of memory setting filters.");
1497 return 0;
1498 }
1499
1500 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001501 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001502 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1503 fp->enabled = false;
1504 } else {
1505 fp->enabled = true;
1506 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001507 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001508 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001509 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001510 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001511 }
1512
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001513 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001514}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001516#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1517 FIF_ALLMULTI | \
1518 FIF_FCSFAIL | \
1519 FIF_BCN_PRBRESP_PROMISC | \
1520 FIF_CONTROL | \
1521 FIF_OTHER_BSS)
1522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1524 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001525 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001527 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001529 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530
1531 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1532
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001533 mutex_lock(&wl->mutex);
1534
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001535 *total &= WL1271_SUPPORTED_FILTERS;
1536 changed &= WL1271_SUPPORTED_FILTERS;
1537
1538 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001539 goto out;
1540
1541 ret = wl1271_ps_elp_wakeup(wl, false);
1542 if (ret < 0)
1543 goto out;
1544
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001546 if (*total & FIF_ALLMULTI)
1547 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1548 else if (fp)
1549 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1550 fp->mc_list,
1551 fp->mc_list_length);
1552 if (ret < 0)
1553 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001555 /* determine, whether supported filter values have changed */
1556 if (changed == 0)
1557 goto out_sleep;
1558
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001559 /* configure filters */
1560 wl->filters = *total;
1561 wl1271_configure_filters(wl, 0);
1562
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001563 /* apply configured filters */
1564 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1565 if (ret < 0)
1566 goto out_sleep;
1567
1568out_sleep:
1569 wl1271_ps_elp_sleep(wl);
1570
1571out:
1572 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001573 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574}
1575
1576static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1577 struct ieee80211_vif *vif,
1578 struct ieee80211_sta *sta,
1579 struct ieee80211_key_conf *key_conf)
1580{
1581 struct wl1271 *wl = hw->priv;
1582 const u8 *addr;
1583 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001584 u32 tx_seq_32 = 0;
1585 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 u8 key_type;
1587
1588 static const u8 bcast_addr[ETH_ALEN] =
1589 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1590
1591 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1592
1593 addr = sta ? sta->addr : bcast_addr;
1594
1595 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1596 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1597 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001598 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001599 key_conf->keylen, key_conf->flags);
1600 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1601
1602 if (is_zero_ether_addr(addr)) {
1603 /* We dont support TX only encryption */
1604 ret = -EOPNOTSUPP;
1605 goto out;
1606 }
1607
1608 mutex_lock(&wl->mutex);
1609
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001610 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1611 ret = -EAGAIN;
1612 goto out_unlock;
1613 }
1614
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 ret = wl1271_ps_elp_wakeup(wl, false);
1616 if (ret < 0)
1617 goto out_unlock;
1618
Johannes Berg97359d12010-08-10 09:46:38 +02001619 switch (key_conf->cipher) {
1620 case WLAN_CIPHER_SUITE_WEP40:
1621 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001622 key_type = KEY_WEP;
1623
1624 key_conf->hw_key_idx = key_conf->keyidx;
1625 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001626 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001627 key_type = KEY_TKIP;
1628
1629 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001630 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1631 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001632 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001633 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001634 key_type = KEY_AES;
1635
1636 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001637 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1638 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001639 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001640 case WL1271_CIPHER_SUITE_GEM:
1641 key_type = KEY_GEM;
1642 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1643 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1644 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001646 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647
1648 ret = -EOPNOTSUPP;
1649 goto out_sleep;
1650 }
1651
1652 switch (cmd) {
1653 case SET_KEY:
1654 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1655 key_conf->keyidx, key_type,
1656 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001657 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658 if (ret < 0) {
1659 wl1271_error("Could not add or replace key");
1660 goto out_sleep;
1661 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001662
1663 /* the default WEP key needs to be configured at least once */
1664 if (key_type == KEY_WEP) {
1665 ret = wl1271_cmd_set_default_wep_key(wl,
1666 wl->default_key);
1667 if (ret < 0)
1668 goto out_sleep;
1669 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670 break;
1671
1672 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001673 /* The wl1271 does not allow to remove unicast keys - they
1674 will be cleared automatically on next CMD_JOIN. Ignore the
1675 request silently, as we dont want the mac80211 to emit
1676 an error message. */
1677 if (!is_broadcast_ether_addr(addr))
1678 break;
1679
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1681 key_conf->keyidx, key_type,
1682 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001683 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684 if (ret < 0) {
1685 wl1271_error("Could not remove key");
1686 goto out_sleep;
1687 }
1688 break;
1689
1690 default:
1691 wl1271_error("Unsupported key cmd 0x%x", cmd);
1692 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 break;
1694 }
1695
1696out_sleep:
1697 wl1271_ps_elp_sleep(wl);
1698
1699out_unlock:
1700 mutex_unlock(&wl->mutex);
1701
1702out:
1703 return ret;
1704}
1705
1706static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001707 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 struct cfg80211_scan_request *req)
1709{
1710 struct wl1271 *wl = hw->priv;
1711 int ret;
1712 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001713 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714
1715 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1716
1717 if (req->n_ssids) {
1718 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001719 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 }
1721
1722 mutex_lock(&wl->mutex);
1723
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001724 if (wl->state == WL1271_STATE_OFF) {
1725 /*
1726 * We cannot return -EBUSY here because cfg80211 will expect
1727 * a call to ieee80211_scan_completed if we do - in this case
1728 * there won't be any call.
1729 */
1730 ret = -EAGAIN;
1731 goto out;
1732 }
1733
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734 ret = wl1271_ps_elp_wakeup(wl, false);
1735 if (ret < 0)
1736 goto out;
1737
Luciano Coelho5924f892010-08-04 03:46:22 +03001738 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739
1740 wl1271_ps_elp_sleep(wl);
1741
1742out:
1743 mutex_unlock(&wl->mutex);
1744
1745 return ret;
1746}
1747
1748static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1749{
1750 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001751 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752
1753 mutex_lock(&wl->mutex);
1754
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001755 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1756 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001757 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001758 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001759
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001760 ret = wl1271_ps_elp_wakeup(wl, false);
1761 if (ret < 0)
1762 goto out;
1763
1764 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1765 if (ret < 0)
1766 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1767
1768 wl1271_ps_elp_sleep(wl);
1769
1770out:
1771 mutex_unlock(&wl->mutex);
1772
1773 return ret;
1774}
1775
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001776static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1777{
1778 u8 *ptr = beacon->data +
1779 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1780
1781 /* find the location of the ssid in the beacon */
1782 while (ptr < beacon->data + beacon->len) {
1783 if (ptr[0] == WLAN_EID_SSID) {
1784 wl->ssid_len = ptr[1];
1785 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1786 return;
1787 }
1788 ptr += ptr[1];
1789 }
1790 wl1271_error("ad-hoc beacon template has no SSID!\n");
1791}
1792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1794 struct ieee80211_vif *vif,
1795 struct ieee80211_bss_conf *bss_conf,
1796 u32 changed)
1797{
1798 enum wl1271_cmd_ps_mode mode;
1799 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001800 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001801 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001802 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 int ret;
1804
1805 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1806
1807 mutex_lock(&wl->mutex);
1808
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001809 if (unlikely(wl->state == WL1271_STATE_OFF))
1810 goto out;
1811
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812 ret = wl1271_ps_elp_wakeup(wl, false);
1813 if (ret < 0)
1814 goto out;
1815
Eliad Peller9ee82d52010-09-19 18:55:09 +02001816 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001817 (wl->bss_type == BSS_TYPE_IBSS)) {
1818 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1819 bss_conf->beacon_int);
1820
1821 wl->beacon_int = bss_conf->beacon_int;
1822 do_join = true;
1823 }
1824
Eliad Peller9ee82d52010-09-19 18:55:09 +02001825 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001826 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001827 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1828
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001829 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1830
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001831 if (beacon) {
1832 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001833
1834 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001835 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1836 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001837 beacon->len, 0,
1838 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001839
1840 if (ret < 0) {
1841 dev_kfree_skb(beacon);
1842 goto out_sleep;
1843 }
1844
1845 hdr = (struct ieee80211_hdr *) beacon->data;
1846 hdr->frame_control = cpu_to_le16(
1847 IEEE80211_FTYPE_MGMT |
1848 IEEE80211_STYPE_PROBE_RESP);
1849
1850 ret = wl1271_cmd_template_set(wl,
1851 CMD_TEMPL_PROBE_RESPONSE,
1852 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001853 beacon->len, 0,
1854 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001855 dev_kfree_skb(beacon);
1856 if (ret < 0)
1857 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001858
1859 /* Need to update the SSID (for filtering etc) */
1860 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001861 }
1862 }
1863
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001864 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1865 (wl->bss_type == BSS_TYPE_IBSS)) {
1866 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1867 bss_conf->enable_beacon ? "enabled" : "disabled");
1868
1869 if (bss_conf->enable_beacon)
1870 wl->set_bss_type = BSS_TYPE_IBSS;
1871 else
1872 wl->set_bss_type = BSS_TYPE_STA_BSS;
1873 do_join = true;
1874 }
1875
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001876 if (changed & BSS_CHANGED_CQM) {
1877 bool enable = false;
1878 if (bss_conf->cqm_rssi_thold)
1879 enable = true;
1880 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1881 bss_conf->cqm_rssi_thold,
1882 bss_conf->cqm_rssi_hyst);
1883 if (ret < 0)
1884 goto out;
1885 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1886 }
1887
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001888 if ((changed & BSS_CHANGED_BSSID) &&
1889 /*
1890 * Now we know the correct bssid, so we send a new join command
1891 * and enable the BSSID filter
1892 */
1893 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001894 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001895
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001896 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001897 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001898 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001899
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001900 ret = wl1271_build_qos_null_data(wl);
1901 if (ret < 0)
1902 goto out_sleep;
1903
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001904 /* filter out all packets not from this BSSID */
1905 wl1271_configure_filters(wl, 0);
1906
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001907 /* Need to update the BSSID (for filtering etc) */
1908 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001909 }
1910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001911 if (changed & BSS_CHANGED_ASSOC) {
1912 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001913 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001915 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001917 wl->ps_poll_failures = 0;
1918
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001919 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001920 * use basic rates from AP, and determine lowest rate
1921 * to use with control frames.
1922 */
1923 rates = bss_conf->basic_rates;
1924 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1925 rates);
1926 wl->basic_rate = wl1271_min_rate_get(wl);
1927 ret = wl1271_acx_rate_policies(wl);
1928 if (ret < 0)
1929 goto out_sleep;
1930
1931 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001932 * with wl1271, we don't need to update the
1933 * beacon_int and dtim_period, because the firmware
1934 * updates it by itself when the first beacon is
1935 * received after a join.
1936 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1938 if (ret < 0)
1939 goto out_sleep;
1940
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001941 /*
1942 * The SSID is intentionally set to NULL here - the
1943 * firmware will set the probe request with a
1944 * broadcast SSID regardless of what we set in the
1945 * template.
1946 */
1947 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1948 NULL, 0, wl->band);
1949
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001950 /* enable the connection monitoring feature */
1951 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 if (ret < 0)
1953 goto out_sleep;
1954
1955 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001956 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1957 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001959 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001960 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001961 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 if (ret < 0)
1963 goto out_sleep;
1964 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001965 } else {
1966 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001967 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001968 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001969 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001970
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001971 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001972 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001973
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001974 /* revert back to minimum rates for the current band */
1975 wl1271_set_band_rate(wl);
1976 wl->basic_rate = wl1271_min_rate_get(wl);
1977 ret = wl1271_acx_rate_policies(wl);
1978 if (ret < 0)
1979 goto out_sleep;
1980
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001981 /* disable connection monitor features */
1982 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001983
1984 /* Disable the keep-alive feature */
1985 ret = wl1271_acx_keep_alive_mode(wl, false);
1986
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001987 if (ret < 0)
1988 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993 if (changed & BSS_CHANGED_ERP_SLOT) {
1994 if (bss_conf->use_short_slot)
1995 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1996 else
1997 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1998 if (ret < 0) {
1999 wl1271_warning("Set slot time failed %d", ret);
2000 goto out_sleep;
2001 }
2002 }
2003
2004 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2005 if (bss_conf->use_short_preamble)
2006 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2007 else
2008 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2009 }
2010
2011 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2012 if (bss_conf->use_cts_prot)
2013 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2014 else
2015 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2016 if (ret < 0) {
2017 wl1271_warning("Set ctsprotect failed %d", ret);
2018 goto out_sleep;
2019 }
2020 }
2021
Shahar Levi18357852010-10-13 16:09:41 +02002022 /*
2023 * Takes care of: New association with HT enable,
2024 * HT information change in beacon.
2025 */
2026 if (sta &&
2027 (changed & BSS_CHANGED_HT) &&
2028 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2029 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2030 if (ret < 0) {
2031 wl1271_warning("Set ht cap true failed %d", ret);
2032 goto out_sleep;
2033 }
2034 ret = wl1271_acx_set_ht_information(wl,
2035 bss_conf->ht_operation_mode);
2036 if (ret < 0) {
2037 wl1271_warning("Set ht information failed %d", ret);
2038 goto out_sleep;
2039 }
2040 }
2041 /*
2042 * Takes care of: New association without HT,
2043 * Disassociation.
2044 */
2045 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2046 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2047 if (ret < 0) {
2048 wl1271_warning("Set ht cap false failed %d", ret);
2049 goto out_sleep;
2050 }
2051 }
2052
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002053 if (changed & BSS_CHANGED_ARP_FILTER) {
2054 __be32 addr = bss_conf->arp_addr_list[0];
2055 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2056
2057 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
2058 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
2059 else
2060 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
2061
2062 if (ret < 0)
2063 goto out_sleep;
2064 }
2065
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002066 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002067 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002068 if (ret < 0) {
2069 wl1271_warning("cmd join failed %d", ret);
2070 goto out_sleep;
2071 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002072 }
2073
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002074out_sleep:
2075 wl1271_ps_elp_sleep(wl);
2076
2077out:
2078 mutex_unlock(&wl->mutex);
2079}
2080
Kalle Valoc6999d82010-02-18 13:25:41 +02002081static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2082 const struct ieee80211_tx_queue_params *params)
2083{
2084 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002085 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002086 int ret;
2087
2088 mutex_lock(&wl->mutex);
2089
2090 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2091
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002092 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2093 ret = -EAGAIN;
2094 goto out;
2095 }
2096
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002097 ret = wl1271_ps_elp_wakeup(wl, false);
2098 if (ret < 0)
2099 goto out;
2100
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002101 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002102 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2103 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002104 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002105 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002106 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002107
Kalle Valo4695dc92010-03-18 12:26:38 +02002108 if (params->uapsd)
2109 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2110 else
2111 ps_scheme = CONF_PS_SCHEME_LEGACY;
2112
Kalle Valoc6999d82010-02-18 13:25:41 +02002113 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2114 CONF_CHANNEL_TYPE_EDCF,
2115 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002116 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002117 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002118 goto out_sleep;
2119
2120out_sleep:
2121 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002122
2123out:
2124 mutex_unlock(&wl->mutex);
2125
2126 return ret;
2127}
2128
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002129static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2130{
2131
2132 struct wl1271 *wl = hw->priv;
2133 u64 mactime = ULLONG_MAX;
2134 int ret;
2135
2136 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2137
2138 mutex_lock(&wl->mutex);
2139
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002140 if (unlikely(wl->state == WL1271_STATE_OFF))
2141 goto out;
2142
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002143 ret = wl1271_ps_elp_wakeup(wl, false);
2144 if (ret < 0)
2145 goto out;
2146
2147 ret = wl1271_acx_tsf_info(wl, &mactime);
2148 if (ret < 0)
2149 goto out_sleep;
2150
2151out_sleep:
2152 wl1271_ps_elp_sleep(wl);
2153
2154out:
2155 mutex_unlock(&wl->mutex);
2156 return mactime;
2157}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158
John W. Linvilleece550d2010-07-28 16:41:06 -04002159static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2160 struct survey_info *survey)
2161{
2162 struct wl1271 *wl = hw->priv;
2163 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002164
John W. Linvilleece550d2010-07-28 16:41:06 -04002165 if (idx != 0)
2166 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002167
John W. Linvilleece550d2010-07-28 16:41:06 -04002168 survey->channel = conf->channel;
2169 survey->filled = SURVEY_INFO_NOISE_DBM;
2170 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002171
John W. Linvilleece550d2010-07-28 16:41:06 -04002172 return 0;
2173}
2174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002175/* can't be const, mac80211 writes to this */
2176static struct ieee80211_rate wl1271_rates[] = {
2177 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002178 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2179 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002181 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2182 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2184 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002185 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2186 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002187 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2188 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002189 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2190 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002191 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2192 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002193 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2194 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002196 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2197 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002198 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002199 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2200 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002202 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2203 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002205 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2206 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002208 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2209 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002211 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2212 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002213 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002214 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2215 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216};
2217
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002218/*
2219 * Can't be const, mac80211 writes to this. The order of the channels here
2220 * is designed to improve scanning.
2221 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002222static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002223 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002224 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002225 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002226 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002227 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2228 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2229 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2230 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2231 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2232 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2233 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2234 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2235 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236};
2237
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002238/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002239static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002240 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002241 7, /* CONF_HW_RXTX_RATE_MCS7 */
2242 6, /* CONF_HW_RXTX_RATE_MCS6 */
2243 5, /* CONF_HW_RXTX_RATE_MCS5 */
2244 4, /* CONF_HW_RXTX_RATE_MCS4 */
2245 3, /* CONF_HW_RXTX_RATE_MCS3 */
2246 2, /* CONF_HW_RXTX_RATE_MCS2 */
2247 1, /* CONF_HW_RXTX_RATE_MCS1 */
2248 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002249
2250 11, /* CONF_HW_RXTX_RATE_54 */
2251 10, /* CONF_HW_RXTX_RATE_48 */
2252 9, /* CONF_HW_RXTX_RATE_36 */
2253 8, /* CONF_HW_RXTX_RATE_24 */
2254
2255 /* TI-specific rate */
2256 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2257
2258 7, /* CONF_HW_RXTX_RATE_18 */
2259 6, /* CONF_HW_RXTX_RATE_12 */
2260 3, /* CONF_HW_RXTX_RATE_11 */
2261 5, /* CONF_HW_RXTX_RATE_9 */
2262 4, /* CONF_HW_RXTX_RATE_6 */
2263 2, /* CONF_HW_RXTX_RATE_5_5 */
2264 1, /* CONF_HW_RXTX_RATE_2 */
2265 0 /* CONF_HW_RXTX_RATE_1 */
2266};
2267
Shahar Levie8b03a22010-10-13 16:09:39 +02002268/* 11n STA capabilities */
2269#define HW_RX_HIGHEST_RATE 72
2270
Shahar Levi00d20102010-11-08 11:20:10 +00002271#ifdef CONFIG_WL12XX_HT
2272#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002273 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2274 .ht_supported = true, \
2275 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2276 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2277 .mcs = { \
2278 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2279 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2280 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2281 }, \
2282}
Shahar Levi18357852010-10-13 16:09:41 +02002283#else
Shahar Levi00d20102010-11-08 11:20:10 +00002284#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002285 .ht_supported = false, \
2286}
2287#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002288
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289/* can't be const, mac80211 writes to this */
2290static struct ieee80211_supported_band wl1271_band_2ghz = {
2291 .channels = wl1271_channels,
2292 .n_channels = ARRAY_SIZE(wl1271_channels),
2293 .bitrates = wl1271_rates,
2294 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002295 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296};
2297
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002298/* 5 GHz data rates for WL1273 */
2299static struct ieee80211_rate wl1271_rates_5ghz[] = {
2300 { .bitrate = 60,
2301 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2302 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2303 { .bitrate = 90,
2304 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2305 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2306 { .bitrate = 120,
2307 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2308 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2309 { .bitrate = 180,
2310 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2311 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2312 { .bitrate = 240,
2313 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2314 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2315 { .bitrate = 360,
2316 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2317 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2318 { .bitrate = 480,
2319 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2320 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2321 { .bitrate = 540,
2322 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2323 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2324};
2325
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002326/*
2327 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2328 * The order of the channels here is designed to improve scanning.
2329 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002330static struct ieee80211_channel wl1271_channels_5ghz[] = {
2331 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002332 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002333 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002334 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002335 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002336 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002337 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002338 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002339 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002340 { .hw_value = 184, .center_freq = 4920},
2341 { .hw_value = 189, .center_freq = 4945},
2342 { .hw_value = 9, .center_freq = 5045},
2343 { .hw_value = 36, .center_freq = 5180},
2344 { .hw_value = 46, .center_freq = 5230},
2345 { .hw_value = 64, .center_freq = 5320},
2346 { .hw_value = 116, .center_freq = 5580},
2347 { .hw_value = 136, .center_freq = 5680},
2348 { .hw_value = 192, .center_freq = 4960},
2349 { .hw_value = 11, .center_freq = 5055},
2350 { .hw_value = 38, .center_freq = 5190},
2351 { .hw_value = 48, .center_freq = 5240},
2352 { .hw_value = 100, .center_freq = 5500},
2353 { .hw_value = 120, .center_freq = 5600},
2354 { .hw_value = 140, .center_freq = 5700},
2355 { .hw_value = 185, .center_freq = 4925},
2356 { .hw_value = 196, .center_freq = 4980},
2357 { .hw_value = 12, .center_freq = 5060},
2358 { .hw_value = 40, .center_freq = 5200},
2359 { .hw_value = 52, .center_freq = 5260},
2360 { .hw_value = 104, .center_freq = 5520},
2361 { .hw_value = 124, .center_freq = 5620},
2362 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002363 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002364 { .hw_value = 187, .center_freq = 4935},
2365 { .hw_value = 7, .center_freq = 5035},
2366 { .hw_value = 16, .center_freq = 5080},
2367 { .hw_value = 42, .center_freq = 5210},
2368 { .hw_value = 56, .center_freq = 5280},
2369 { .hw_value = 108, .center_freq = 5540},
2370 { .hw_value = 128, .center_freq = 5640},
2371 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002372 { .hw_value = 165, .center_freq = 5825},
2373};
2374
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002375/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002376static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002377 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002378 7, /* CONF_HW_RXTX_RATE_MCS7 */
2379 6, /* CONF_HW_RXTX_RATE_MCS6 */
2380 5, /* CONF_HW_RXTX_RATE_MCS5 */
2381 4, /* CONF_HW_RXTX_RATE_MCS4 */
2382 3, /* CONF_HW_RXTX_RATE_MCS3 */
2383 2, /* CONF_HW_RXTX_RATE_MCS2 */
2384 1, /* CONF_HW_RXTX_RATE_MCS1 */
2385 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002386
2387 7, /* CONF_HW_RXTX_RATE_54 */
2388 6, /* CONF_HW_RXTX_RATE_48 */
2389 5, /* CONF_HW_RXTX_RATE_36 */
2390 4, /* CONF_HW_RXTX_RATE_24 */
2391
2392 /* TI-specific rate */
2393 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2394
2395 3, /* CONF_HW_RXTX_RATE_18 */
2396 2, /* CONF_HW_RXTX_RATE_12 */
2397 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2398 1, /* CONF_HW_RXTX_RATE_9 */
2399 0, /* CONF_HW_RXTX_RATE_6 */
2400 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2401 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2402 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2403};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002404
2405static struct ieee80211_supported_band wl1271_band_5ghz = {
2406 .channels = wl1271_channels_5ghz,
2407 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2408 .bitrates = wl1271_rates_5ghz,
2409 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002410 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002411};
2412
Tobias Klausera0ea9492010-05-20 10:38:11 +02002413static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002414 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2415 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2416};
2417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418static const struct ieee80211_ops wl1271_ops = {
2419 .start = wl1271_op_start,
2420 .stop = wl1271_op_stop,
2421 .add_interface = wl1271_op_add_interface,
2422 .remove_interface = wl1271_op_remove_interface,
2423 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002424 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002425 .configure_filter = wl1271_op_configure_filter,
2426 .tx = wl1271_op_tx,
2427 .set_key = wl1271_op_set_key,
2428 .hw_scan = wl1271_op_hw_scan,
2429 .bss_info_changed = wl1271_op_bss_info_changed,
2430 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002431 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002432 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002433 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002434 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002435};
2436
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002437
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002438u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002439{
2440 u8 idx;
2441
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002442 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002443
2444 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2445 wl1271_error("Illegal RX rate from HW: %d", rate);
2446 return 0;
2447 }
2448
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002449 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002450 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2451 wl1271_error("Unsupported RX rate from HW: %d", rate);
2452 return 0;
2453 }
2454
2455 return idx;
2456}
2457
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002458static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2459 struct device_attribute *attr,
2460 char *buf)
2461{
2462 struct wl1271 *wl = dev_get_drvdata(dev);
2463 ssize_t len;
2464
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002465 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002466
2467 mutex_lock(&wl->mutex);
2468 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2469 wl->sg_enabled);
2470 mutex_unlock(&wl->mutex);
2471
2472 return len;
2473
2474}
2475
2476static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2477 struct device_attribute *attr,
2478 const char *buf, size_t count)
2479{
2480 struct wl1271 *wl = dev_get_drvdata(dev);
2481 unsigned long res;
2482 int ret;
2483
2484 ret = strict_strtoul(buf, 10, &res);
2485
2486 if (ret < 0) {
2487 wl1271_warning("incorrect value written to bt_coex_mode");
2488 return count;
2489 }
2490
2491 mutex_lock(&wl->mutex);
2492
2493 res = !!res;
2494
2495 if (res == wl->sg_enabled)
2496 goto out;
2497
2498 wl->sg_enabled = res;
2499
2500 if (wl->state == WL1271_STATE_OFF)
2501 goto out;
2502
2503 ret = wl1271_ps_elp_wakeup(wl, false);
2504 if (ret < 0)
2505 goto out;
2506
2507 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2508 wl1271_ps_elp_sleep(wl);
2509
2510 out:
2511 mutex_unlock(&wl->mutex);
2512 return count;
2513}
2514
2515static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2516 wl1271_sysfs_show_bt_coex_state,
2517 wl1271_sysfs_store_bt_coex_state);
2518
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002519static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2520 struct device_attribute *attr,
2521 char *buf)
2522{
2523 struct wl1271 *wl = dev_get_drvdata(dev);
2524 ssize_t len;
2525
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002526 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002527
2528 mutex_lock(&wl->mutex);
2529 if (wl->hw_pg_ver >= 0)
2530 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2531 else
2532 len = snprintf(buf, len, "n/a\n");
2533 mutex_unlock(&wl->mutex);
2534
2535 return len;
2536}
2537
2538static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2539 wl1271_sysfs_show_hw_pg_ver, NULL);
2540
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002541int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542{
2543 int ret;
2544
2545 if (wl->mac80211_registered)
2546 return 0;
2547
2548 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2549
2550 ret = ieee80211_register_hw(wl->hw);
2551 if (ret < 0) {
2552 wl1271_error("unable to register mac80211 hw: %d", ret);
2553 return ret;
2554 }
2555
2556 wl->mac80211_registered = true;
2557
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002558 register_netdevice_notifier(&wl1271_dev_notifier);
2559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560 wl1271_notice("loaded");
2561
2562 return 0;
2563}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002564EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002566void wl1271_unregister_hw(struct wl1271 *wl)
2567{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002568 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002569 ieee80211_unregister_hw(wl->hw);
2570 wl->mac80211_registered = false;
2571
2572}
2573EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2574
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002575int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002577 static const u32 cipher_suites[] = {
2578 WLAN_CIPHER_SUITE_WEP40,
2579 WLAN_CIPHER_SUITE_WEP104,
2580 WLAN_CIPHER_SUITE_TKIP,
2581 WLAN_CIPHER_SUITE_CCMP,
2582 WL1271_CIPHER_SUITE_GEM,
2583 };
2584
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002585 /* The tx descriptor buffer and the TKIP space. */
2586 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2587 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588
2589 /* unit us */
2590 /* FIXME: find a proper value */
2591 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002592 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002593
2594 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002595 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002596 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002597 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002598 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002599 IEEE80211_HW_CONNECTION_MONITOR |
2600 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002601
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002602 wl->hw->wiphy->cipher_suites = cipher_suites;
2603 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2604
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002605 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2606 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002607 wl->hw->wiphy->max_scan_ssids = 1;
2608 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002609 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002610
Kalle Valo12bd8942010-03-18 12:26:33 +02002611 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002612 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002613
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002614 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2615
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002616 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002617
2618 return 0;
2619}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002620EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002621
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002622#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002623
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002624struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002625{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002626 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002627 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002628 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002629 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002630 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002631
2632 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2633 if (!hw) {
2634 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002635 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002636 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637 }
2638
Julia Lawall929ebd32010-05-15 23:16:39 +02002639 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002640 if (!plat_dev) {
2641 wl1271_error("could not allocate platform_device");
2642 ret = -ENOMEM;
2643 goto err_plat_alloc;
2644 }
2645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646 wl = hw->priv;
2647 memset(wl, 0, sizeof(*wl));
2648
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002649 INIT_LIST_HEAD(&wl->list);
2650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002651 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002652 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002653
2654 skb_queue_head_init(&wl->tx_queue);
2655
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002656 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002657 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002658 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2659 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2660 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2661 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002662 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002663 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002664 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665 wl->rx_counter = 0;
2666 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2667 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002668 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002669 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002670 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002671 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002672 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2673 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002674 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002675 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002676 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002677 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002678 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002680 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002681 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682 wl->tx_frames[i] = NULL;
2683
2684 spin_lock_init(&wl->wl_lock);
2685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 wl->state = WL1271_STATE_OFF;
2687 mutex_init(&wl->mutex);
2688
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002689 /* Apply default driver configuration. */
2690 wl1271_conf_init(wl);
2691
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002692 wl1271_debugfs_init(wl);
2693
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002694 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2695 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2696 if (!wl->aggr_buf) {
2697 ret = -ENOMEM;
2698 goto err_hw;
2699 }
2700
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002701 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002702 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002703 if (ret) {
2704 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002705 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002706 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002707 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002708
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002709 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002710 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002711 if (ret < 0) {
2712 wl1271_error("failed to create sysfs file bt_coex_state");
2713 goto err_platform;
2714 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002715
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002716 /* Create sysfs file to get HW PG version */
2717 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2718 if (ret < 0) {
2719 wl1271_error("failed to create sysfs file hw_pg_ver");
2720 goto err_bt_coex_state;
2721 }
2722
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002723 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002724
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002725err_bt_coex_state:
2726 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2727
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002728err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002729 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002730
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002731err_aggr:
2732 free_pages((unsigned long)wl->aggr_buf, order);
2733
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002734err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002735 wl1271_debugfs_exit(wl);
2736 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002737
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002738err_plat_alloc:
2739 ieee80211_free_hw(hw);
2740
2741err_hw_alloc:
2742
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002743 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002744}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002745EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002746
2747int wl1271_free_hw(struct wl1271 *wl)
2748{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002749 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002750 free_pages((unsigned long)wl->aggr_buf,
2751 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002752 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002753
2754 wl1271_debugfs_exit(wl);
2755
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002756 vfree(wl->fw);
2757 wl->fw = NULL;
2758 kfree(wl->nvs);
2759 wl->nvs = NULL;
2760
2761 kfree(wl->fw_status);
2762 kfree(wl->tx_res_if);
2763
2764 ieee80211_free_hw(wl->hw);
2765
2766 return 0;
2767}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002768EXPORT_SYMBOL_GPL(wl1271_free_hw);
2769
2770MODULE_LICENSE("GPL");
2771MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2772MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");