blob: 062247ef3ad2742378c7993649eef5780842c665 [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,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200339 struct regulatory_request *request)
340{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100341 struct ieee80211_supported_band *band;
342 struct ieee80211_channel *ch;
343 int i;
344
345 band = wiphy->bands[IEEE80211_BAND_5GHZ];
346 for (i = 0; i < band->n_channels; i++) {
347 ch = &band->channels[i];
348 if (ch->flags & IEEE80211_CHAN_DISABLED)
349 continue;
350
351 if (ch->flags & IEEE80211_CHAN_RADAR)
352 ch->flags |= IEEE80211_CHAN_NO_IBSS |
353 IEEE80211_CHAN_PASSIVE_SCAN;
354
355 }
356
357 return 0;
358}
359
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300360static void wl1271_conf_init(struct wl1271 *wl)
361{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300362
363 /*
364 * This function applies the default configuration to the driver. This
365 * function is invoked upon driver load (spi probe.)
366 *
367 * The configuration is stored in a run-time structure in order to
368 * facilitate for run-time adjustment of any of the parameters. Making
369 * changes to the configuration structure will apply the new values on
370 * the next interface up (wl1271_op_start.)
371 */
372
373 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300375}
376
377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378static int wl1271_plt_init(struct wl1271 *wl)
379{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200380 struct conf_tx_ac_category *conf_ac;
381 struct conf_tx_tid *conf_tid;
382 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300383
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200384 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200385 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200386 return ret;
387
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200388 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200389 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200390 return ret;
391
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200392 ret = wl1271_cmd_ext_radio_parms(wl);
393 if (ret < 0)
394 return ret;
395
Luciano Coelho12419cc2010-02-18 13:25:44 +0200396 ret = wl1271_init_templates_config(wl);
397 if (ret < 0)
398 return ret;
399
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400 ret = wl1271_acx_init_mem_config(wl);
401 if (ret < 0)
402 return ret;
403
Luciano Coelho12419cc2010-02-18 13:25:44 +0200404 /* PHY layer config */
405 ret = wl1271_init_phy_config(wl);
406 if (ret < 0)
407 goto out_free_memmap;
408
409 ret = wl1271_acx_dco_itrim_params(wl);
410 if (ret < 0)
411 goto out_free_memmap;
412
413 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200414 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200415 if (ret < 0)
416 goto out_free_memmap;
417
418 /* Bluetooth WLAN coexistence */
419 ret = wl1271_init_pta(wl);
420 if (ret < 0)
421 goto out_free_memmap;
422
423 /* Energy detection */
424 ret = wl1271_init_energy_detection(wl);
425 if (ret < 0)
426 goto out_free_memmap;
427
428 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100429 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200430 if (ret < 0)
431 goto out_free_memmap;
432
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200433 /* Default TID/AC configuration */
434 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200435 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200436 conf_ac = &wl->conf.tx.ac_conf[i];
437 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
438 conf_ac->cw_max, conf_ac->aifsn,
439 conf_ac->tx_op_limit);
440 if (ret < 0)
441 goto out_free_memmap;
442
Luciano Coelho12419cc2010-02-18 13:25:44 +0200443 conf_tid = &wl->conf.tx.tid_conf[i];
444 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
445 conf_tid->channel_type,
446 conf_tid->tsid,
447 conf_tid->ps_scheme,
448 conf_tid->ack_policy,
449 conf_tid->apsd_conf[0],
450 conf_tid->apsd_conf[1]);
451 if (ret < 0)
452 goto out_free_memmap;
453 }
454
Luciano Coelho12419cc2010-02-18 13:25:44 +0200455 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200456 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200458 goto out_free_memmap;
459
460 /* Configure for CAM power saving (ie. always active) */
461 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
462 if (ret < 0)
463 goto out_free_memmap;
464
465 /* configure PM */
466 ret = wl1271_acx_pm_config(wl);
467 if (ret < 0)
468 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300469
470 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200471
472 out_free_memmap:
473 kfree(wl->target_mem_map);
474 wl->target_mem_map = NULL;
475
476 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477}
478
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300479static void wl1271_fw_status(struct wl1271 *wl,
480 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200482 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483 u32 total = 0;
484 int i;
485
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200486 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
489 "drv_rx_counter = %d, tx_results_counter = %d)",
490 status->intr,
491 status->fw_rx_counter,
492 status->drv_rx_counter,
493 status->tx_results_counter);
494
495 /* update number of available TX blocks */
496 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300497 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
498 wl->tx_blocks_freed[i];
499
500 wl->tx_blocks_freed[i] =
501 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 wl->tx_blocks_available += cnt;
503 total += cnt;
504 }
505
Ido Yariva5225502010-10-12 14:49:10 +0200506 /* if more blocks are available now, tx work can be scheduled */
507 if (total)
508 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300509
510 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200511 getnstimeofday(&ts);
512 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
513 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514}
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516#define WL1271_IRQ_MAX_LOOPS 10
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518static void wl1271_irq_work(struct work_struct *work)
519{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300520 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300521 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200522 int loopcount = WL1271_IRQ_MAX_LOOPS;
523 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524 struct wl1271 *wl =
525 container_of(work, struct wl1271, irq_work);
526
527 mutex_lock(&wl->mutex);
528
529 wl1271_debug(DEBUG_IRQ, "IRQ work");
530
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200531 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300532 goto out;
533
534 ret = wl1271_ps_elp_wakeup(wl, true);
535 if (ret < 0)
536 goto out;
537
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200538 spin_lock_irqsave(&wl->wl_lock, flags);
539 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
540 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
541 spin_unlock_irqrestore(&wl->wl_lock, flags);
542 loopcount--;
543
544 wl1271_fw_status(wl, wl->fw_status);
545 intr = le32_to_cpu(wl->fw_status->intr);
546 if (!intr) {
547 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200548 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200549 continue;
550 }
551
552 intr &= WL1271_INTR_MASK;
553
Eliad Pellerccc83b02010-10-27 14:09:57 +0200554 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
555 wl1271_error("watchdog interrupt received! "
556 "starting recovery.");
557 ieee80211_queue_work(wl->hw, &wl->recovery_work);
558
559 /* restarting the chip. ignore any other interrupt. */
560 goto out;
561 }
562
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200563 if (intr & WL1271_ACX_INTR_DATA) {
564 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
565
566 /* check for tx results */
567 if (wl->fw_status->tx_results_counter !=
568 (wl->tx_results_count & 0xff))
569 wl1271_tx_complete(wl);
570
Ido Yariva5225502010-10-12 14:49:10 +0200571 /* Check if any tx blocks were freed */
572 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200573 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200574 /*
575 * In order to avoid starvation of the TX path,
576 * call the work function directly.
577 */
578 wl1271_tx_work_locked(wl);
579 }
580
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200581 wl1271_rx(wl, wl->fw_status);
582 }
583
584 if (intr & WL1271_ACX_INTR_EVENT_A) {
585 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
586 wl1271_event_handle(wl, 0);
587 }
588
589 if (intr & WL1271_ACX_INTR_EVENT_B) {
590 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
591 wl1271_event_handle(wl, 1);
592 }
593
594 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
595 wl1271_debug(DEBUG_IRQ,
596 "WL1271_ACX_INTR_INIT_COMPLETE");
597
598 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
599 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
600
601 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602 }
603
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200604 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
605 ieee80211_queue_work(wl->hw, &wl->irq_work);
606 else
607 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
608 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300610 wl1271_ps_elp_sleep(wl);
611
612out:
613 mutex_unlock(&wl->mutex);
614}
615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300616static int wl1271_fetch_firmware(struct wl1271 *wl)
617{
618 const struct firmware *fw;
619 int ret;
620
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200621 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622
623 if (ret < 0) {
624 wl1271_error("could not get firmware: %d", ret);
625 return ret;
626 }
627
628 if (fw->size % 4) {
629 wl1271_error("firmware size is not multiple of 32 bits: %zu",
630 fw->size);
631 ret = -EILSEQ;
632 goto out;
633 }
634
635 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300636 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637
638 if (!wl->fw) {
639 wl1271_error("could not allocate memory for the firmware");
640 ret = -ENOMEM;
641 goto out;
642 }
643
644 memcpy(wl->fw, fw->data, wl->fw_len);
645
646 ret = 0;
647
648out:
649 release_firmware(fw);
650
651 return ret;
652}
653
654static int wl1271_fetch_nvs(struct wl1271 *wl)
655{
656 const struct firmware *fw;
657 int ret;
658
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200659 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660
661 if (ret < 0) {
662 wl1271_error("could not get nvs file: %d", ret);
663 return ret;
664 }
665
Julia Lawall929ebd32010-05-15 23:16:39 +0200666 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667
668 if (!wl->nvs) {
669 wl1271_error("could not allocate memory for the nvs file");
670 ret = -ENOMEM;
671 goto out;
672 }
673
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200674 wl->nvs_len = fw->size;
675
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676out:
677 release_firmware(fw);
678
679 return ret;
680}
681
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200682static void wl1271_recovery_work(struct work_struct *work)
683{
684 struct wl1271 *wl =
685 container_of(work, struct wl1271, recovery_work);
686
687 mutex_lock(&wl->mutex);
688
689 if (wl->state != WL1271_STATE_ON)
690 goto out;
691
692 wl1271_info("Hardware recovery in progress.");
693
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200694 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
695 ieee80211_connection_loss(wl->vif);
696
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200697 /* reboot the chipset */
698 __wl1271_op_remove_interface(wl);
699 ieee80211_restart_hw(wl->hw);
700
701out:
702 mutex_unlock(&wl->mutex);
703}
704
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705static void wl1271_fw_wakeup(struct wl1271 *wl)
706{
707 u32 elp_reg;
708
709 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300710 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711}
712
713static int wl1271_setup(struct wl1271 *wl)
714{
715 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
716 if (!wl->fw_status)
717 return -ENOMEM;
718
719 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
720 if (!wl->tx_res_if) {
721 kfree(wl->fw_status);
722 return -ENOMEM;
723 }
724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725 return 0;
726}
727
728static int wl1271_chip_wakeup(struct wl1271 *wl)
729{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300730 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731 int ret = 0;
732
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200733 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200734 ret = wl1271_power_on(wl);
735 if (ret < 0)
736 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200738 wl1271_io_reset(wl);
739 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740
741 /* We don't need a real memory partition here, because we only want
742 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300743 memset(&partition, 0, sizeof(partition));
744 partition.reg.start = REGISTERS_BASE;
745 partition.reg.size = REGISTERS_DOWN_SIZE;
746 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747
748 /* ELP module wake up */
749 wl1271_fw_wakeup(wl);
750
751 /* whal_FwCtrl_BootSm() */
752
753 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200754 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300755
756 /* 1. check if chip id is valid */
757
758 switch (wl->chip.id) {
759 case CHIP_ID_1271_PG10:
760 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
761 wl->chip.id);
762
763 ret = wl1271_setup(wl);
764 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200765 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766 break;
767 case CHIP_ID_1271_PG20:
768 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
769 wl->chip.id);
770
771 ret = wl1271_setup(wl);
772 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200773 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774 break;
775 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200776 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200778 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 }
780
781 if (wl->fw == NULL) {
782 ret = wl1271_fetch_firmware(wl);
783 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200784 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 }
786
787 /* No NVS from netlink, try to get it from the filesystem */
788 if (wl->nvs == NULL) {
789 ret = wl1271_fetch_nvs(wl);
790 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200791 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792 }
793
794out:
795 return ret;
796}
797
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798int wl1271_plt_start(struct wl1271 *wl)
799{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200800 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300801 int ret;
802
803 mutex_lock(&wl->mutex);
804
805 wl1271_notice("power up");
806
807 if (wl->state != WL1271_STATE_OFF) {
808 wl1271_error("cannot go into PLT state because not "
809 "in off state: %d", wl->state);
810 ret = -EBUSY;
811 goto out;
812 }
813
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200814 while (retries) {
815 retries--;
816 ret = wl1271_chip_wakeup(wl);
817 if (ret < 0)
818 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200820 ret = wl1271_boot(wl);
821 if (ret < 0)
822 goto power_off;
823
824 ret = wl1271_plt_init(wl);
825 if (ret < 0)
826 goto irq_disable;
827
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200828 wl->state = WL1271_STATE_PLT;
829 wl1271_notice("firmware booted in PLT mode (%s)",
830 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831 goto out;
832
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200833irq_disable:
834 wl1271_disable_interrupts(wl);
835 mutex_unlock(&wl->mutex);
836 /* Unlocking the mutex in the middle of handling is
837 inherently unsafe. In this case we deem it safe to do,
838 because we need to let any possibly pending IRQ out of
839 the system (and while we are WL1271_STATE_OFF the IRQ
840 work function will not do anything.) Also, any other
841 possible concurrent operations will fail due to the
842 current state, hence the wl1271 struct should be safe. */
843 cancel_work_sync(&wl->irq_work);
844 mutex_lock(&wl->mutex);
845power_off:
846 wl1271_power_off(wl);
847 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200849 wl1271_error("firmware boot in PLT mode failed despite %d retries",
850 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851out:
852 mutex_unlock(&wl->mutex);
853
854 return ret;
855}
856
857int wl1271_plt_stop(struct wl1271 *wl)
858{
859 int ret = 0;
860
861 mutex_lock(&wl->mutex);
862
863 wl1271_notice("power down");
864
865 if (wl->state != WL1271_STATE_PLT) {
866 wl1271_error("cannot power down because not in PLT "
867 "state: %d", wl->state);
868 ret = -EBUSY;
869 goto out;
870 }
871
872 wl1271_disable_interrupts(wl);
873 wl1271_power_off(wl);
874
875 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300876 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877
878out:
879 mutex_unlock(&wl->mutex);
880
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200881 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200882 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200883
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884 return ret;
885}
886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
888{
889 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200890 struct ieee80211_conf *conf = &hw->conf;
891 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
892 struct ieee80211_sta *sta = txinfo->control.sta;
893 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200894 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
Shahar Levi18357852010-10-13 16:09:41 +0200896 /*
897 * peek into the rates configured in the STA entry.
898 * The rates set after connection stage, The first block only BG sets:
899 * the compare is for bit 0-16 of sta_rate_set. The second block add
900 * HT rates in case of HT supported.
901 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200902 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200903 if (sta &&
904 (sta->supp_rates[conf->channel->band] !=
905 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200906 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
907 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
908 }
Shahar Levi18357852010-10-13 16:09:41 +0200909
Shahar Levi00d20102010-11-08 11:20:10 +0000910#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200911 if (sta &&
912 sta->ht_cap.ht_supported &&
913 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
914 sta->ht_cap.mcs.rx_mask[0])) {
915 /* Clean MCS bits before setting them */
916 wl->sta_rate_set &= HW_BG_RATES_MASK;
917 wl->sta_rate_set |=
918 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
919 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
920 }
921#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200922 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200923 spin_unlock_irqrestore(&wl->wl_lock, flags);
924
925 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200926 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
927 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928
929 /*
930 * The chip specific setup must run before the first TX packet -
931 * before that, the tx_work will not be initialized!
932 */
933
Ido Yariva5225502010-10-12 14:49:10 +0200934 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
935 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
937 /*
938 * The workqueue is slow to process the tx_queue and we need stop
939 * the queue here, otherwise the queue will get too long.
940 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200941 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200942 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200944 spin_lock_irqsave(&wl->wl_lock, flags);
945 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200946 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200947 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 }
949
950 return NETDEV_TX_OK;
951}
952
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300953static struct notifier_block wl1271_dev_notifier = {
954 .notifier_call = wl1271_dev_notify,
955};
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957static int wl1271_op_start(struct ieee80211_hw *hw)
958{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200959 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
960
961 /*
962 * We have to delay the booting of the hardware because
963 * we need to know the local MAC address before downloading and
964 * initializing the firmware. The MAC address cannot be changed
965 * after boot, and without the proper MAC address, the firmware
966 * will not function properly.
967 *
968 * The MAC address is first known when the corresponding interface
969 * is added. That is where we will initialize the hardware.
970 */
971
972 return 0;
973}
974
975static void wl1271_op_stop(struct ieee80211_hw *hw)
976{
977 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
978}
979
980static int wl1271_op_add_interface(struct ieee80211_hw *hw,
981 struct ieee80211_vif *vif)
982{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400984 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200985 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +0200987 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200989 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
990 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991
992 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200993 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +0200994 wl1271_debug(DEBUG_MAC80211,
995 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200996 ret = -EBUSY;
997 goto out;
998 }
999
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001000 switch (vif->type) {
1001 case NL80211_IFTYPE_STATION:
1002 wl->bss_type = BSS_TYPE_STA_BSS;
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 case NL80211_IFTYPE_ADHOC:
1006 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001007 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001008 break;
1009 default:
1010 ret = -EOPNOTSUPP;
1011 goto out;
1012 }
1013
1014 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015
1016 if (wl->state != WL1271_STATE_OFF) {
1017 wl1271_error("cannot start because not in off state: %d",
1018 wl->state);
1019 ret = -EBUSY;
1020 goto out;
1021 }
1022
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001023 while (retries) {
1024 retries--;
1025 ret = wl1271_chip_wakeup(wl);
1026 if (ret < 0)
1027 goto power_off;
1028
1029 ret = wl1271_boot(wl);
1030 if (ret < 0)
1031 goto power_off;
1032
1033 ret = wl1271_hw_init(wl);
1034 if (ret < 0)
1035 goto irq_disable;
1036
Eliad Peller71125ab2010-10-28 21:46:43 +02001037 booted = true;
1038 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001040irq_disable:
1041 wl1271_disable_interrupts(wl);
1042 mutex_unlock(&wl->mutex);
1043 /* Unlocking the mutex in the middle of handling is
1044 inherently unsafe. In this case we deem it safe to do,
1045 because we need to let any possibly pending IRQ out of
1046 the system (and while we are WL1271_STATE_OFF the IRQ
1047 work function will not do anything.) Also, any other
1048 possible concurrent operations will fail due to the
1049 current state, hence the wl1271 struct should be safe. */
1050 cancel_work_sync(&wl->irq_work);
1051 mutex_lock(&wl->mutex);
1052power_off:
1053 wl1271_power_off(wl);
1054 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
Eliad Peller71125ab2010-10-28 21:46:43 +02001056 if (!booted) {
1057 wl1271_error("firmware boot failed despite %d retries",
1058 WL1271_BOOT_RETRIES);
1059 goto out;
1060 }
1061
1062 wl->vif = vif;
1063 wl->state = WL1271_STATE_ON;
1064 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1065
1066 /* update hw/fw version info in wiphy struct */
1067 wiphy->hw_version = wl->chip.id;
1068 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1069 sizeof(wiphy->fw_version));
1070
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001071 /*
1072 * Now we know if 11a is supported (info from the NVS), so disable
1073 * 11a channels if not supported
1074 */
1075 if (!wl->enable_11a)
1076 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1077
1078 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1079 wl->enable_11a ? "" : "not ");
1080
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001081out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 mutex_unlock(&wl->mutex);
1083
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001084 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001085 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001086
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087 return ret;
1088}
1089
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001090static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 int i;
1093
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001094 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001096 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001098 list_del(&wl->list);
1099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 WARN_ON(wl->state != WL1271_STATE_ON);
1101
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001102 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001103 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001104 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001105
Luciano Coelho08688d62010-07-08 17:50:07 +03001106 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001107 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1108 kfree(wl->scan.scanned_ch);
1109 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001110 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001111 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 }
1113
1114 wl->state = WL1271_STATE_OFF;
1115
1116 wl1271_disable_interrupts(wl);
1117
1118 mutex_unlock(&wl->mutex);
1119
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001120 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121 cancel_work_sync(&wl->irq_work);
1122 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001123 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001124 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125
1126 mutex_lock(&wl->mutex);
1127
1128 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001129 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130 wl1271_power_off(wl);
1131
1132 memset(wl->bssid, 0, ETH_ALEN);
1133 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1134 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001136 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001137 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138
1139 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001140 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1142 wl->tx_blocks_available = 0;
1143 wl->tx_results_count = 0;
1144 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001145 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001146 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147 wl->time_offset = 0;
1148 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001149 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1150 wl->sta_rate_set = 0;
1151 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001152 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001153 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001154
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001155 for (i = 0; i < NUM_TX_QUEUES; i++)
1156 wl->tx_blocks_freed[i] = 0;
1157
1158 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001159
1160 kfree(wl->fw_status);
1161 wl->fw_status = NULL;
1162 kfree(wl->tx_res_if);
1163 wl->tx_res_if = NULL;
1164 kfree(wl->target_mem_map);
1165 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001166}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001167
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001168static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1169 struct ieee80211_vif *vif)
1170{
1171 struct wl1271 *wl = hw->priv;
1172
1173 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001174 /*
1175 * wl->vif can be null here if someone shuts down the interface
1176 * just when hardware recovery has been started.
1177 */
1178 if (wl->vif) {
1179 WARN_ON(wl->vif != vif);
1180 __wl1271_op_remove_interface(wl);
1181 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001182
Juuso Oikarinen67353292010-11-18 15:19:02 +02001183 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001184 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185}
1186
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001187static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1188{
1189 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1190 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1191
1192 /* combine requested filters with current filter config */
1193 filters = wl->filters | filters;
1194
1195 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1196
1197 if (filters & FIF_PROMISC_IN_BSS) {
1198 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1199 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1200 wl->rx_config |= CFG_BSSID_FILTER_EN;
1201 }
1202 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1203 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1204 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1205 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1206 }
1207 if (filters & FIF_OTHER_BSS) {
1208 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1209 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1210 }
1211 if (filters & FIF_CONTROL) {
1212 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1213 wl->rx_filter |= CFG_RX_CTL_EN;
1214 }
1215 if (filters & FIF_FCSFAIL) {
1216 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1217 wl->rx_filter |= CFG_RX_FCS_ERROR;
1218 }
1219}
1220
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001221static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001222{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001223 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001224 /* we need to use a dummy BSSID for now */
1225 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1226 0xad, 0xbe, 0xef };
1227
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001228 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1229
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001230 /* pass through frames from all BSS */
1231 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1232
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001233 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001234 if (ret < 0)
1235 goto out;
1236
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001237 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001238
1239out:
1240 return ret;
1241}
1242
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001243static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001244{
1245 int ret;
1246
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001247 /*
1248 * One of the side effects of the JOIN command is that is clears
1249 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1250 * to a WPA/WPA2 access point will therefore kill the data-path.
1251 * Currently there is no supported scenario for JOIN during
1252 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1253 * must be handled somehow.
1254 *
1255 */
1256 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1257 wl1271_info("JOIN while associated.");
1258
1259 if (set_assoc)
1260 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1261
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001262 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1263 if (ret < 0)
1264 goto out;
1265
1266 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1267
1268 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1269 goto out;
1270
1271 /*
1272 * The join command disable the keep-alive mode, shut down its process,
1273 * and also clear the template config, so we need to reset it all after
1274 * the join. The acx_aid starts the keep-alive process, and the order
1275 * of the commands below is relevant.
1276 */
1277 ret = wl1271_acx_keep_alive_mode(wl, true);
1278 if (ret < 0)
1279 goto out;
1280
1281 ret = wl1271_acx_aid(wl, wl->aid);
1282 if (ret < 0)
1283 goto out;
1284
1285 ret = wl1271_cmd_build_klv_null_data(wl);
1286 if (ret < 0)
1287 goto out;
1288
1289 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1290 ACX_KEEP_ALIVE_TPL_VALID);
1291 if (ret < 0)
1292 goto out;
1293
1294out:
1295 return ret;
1296}
1297
1298static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001299{
1300 int ret;
1301
1302 /* to stop listening to a channel, we disconnect */
1303 ret = wl1271_cmd_disconnect(wl);
1304 if (ret < 0)
1305 goto out;
1306
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001307 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001308 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001309
1310 /* stop filterting packets based on bssid */
1311 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001312
1313out:
1314 return ret;
1315}
1316
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001317static void wl1271_set_band_rate(struct wl1271 *wl)
1318{
1319 if (wl->band == IEEE80211_BAND_2GHZ)
1320 wl->basic_rate_set = wl->conf.tx.basic_rate;
1321 else
1322 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1323}
1324
1325static u32 wl1271_min_rate_get(struct wl1271 *wl)
1326{
1327 int i;
1328 u32 rate = 0;
1329
1330 if (!wl->basic_rate_set) {
1331 WARN_ON(1);
1332 wl->basic_rate_set = wl->conf.tx.basic_rate;
1333 }
1334
1335 for (i = 0; !rate; i++) {
1336 if ((wl->basic_rate_set >> i) & 0x1)
1337 rate = 1 << i;
1338 }
1339
1340 return rate;
1341}
1342
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001343static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1344{
1345 int ret;
1346
1347 if (idle) {
1348 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1349 ret = wl1271_unjoin(wl);
1350 if (ret < 0)
1351 goto out;
1352 }
1353 wl->rate_set = wl1271_min_rate_get(wl);
1354 wl->sta_rate_set = 0;
1355 ret = wl1271_acx_rate_policies(wl);
1356 if (ret < 0)
1357 goto out;
1358 ret = wl1271_acx_keep_alive_config(
1359 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1360 ACX_KEEP_ALIVE_TPL_INVALID);
1361 if (ret < 0)
1362 goto out;
1363 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1364 } else {
1365 /* increment the session counter */
1366 wl->session_counter++;
1367 if (wl->session_counter >= SESSION_COUNTER_MAX)
1368 wl->session_counter = 0;
1369 ret = wl1271_dummy_join(wl);
1370 if (ret < 0)
1371 goto out;
1372 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1373 }
1374
1375out:
1376 return ret;
1377}
1378
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1380{
1381 struct wl1271 *wl = hw->priv;
1382 struct ieee80211_conf *conf = &hw->conf;
1383 int channel, ret = 0;
1384
1385 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1386
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001387 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388 channel,
1389 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001390 conf->power_level,
1391 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001393 /*
1394 * mac80211 will go to idle nearly immediately after transmitting some
1395 * frames, such as the deauth. To make sure those frames reach the air,
1396 * wait here until the TX queue is fully flushed.
1397 */
1398 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1399 (conf->flags & IEEE80211_CONF_IDLE))
1400 wl1271_tx_flush(wl);
1401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 mutex_lock(&wl->mutex);
1403
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001404 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1405 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001406 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001407 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409 ret = wl1271_ps_elp_wakeup(wl, false);
1410 if (ret < 0)
1411 goto out;
1412
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001413 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001414 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1415 ((wl->band != conf->channel->band) ||
1416 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001417 wl->band = conf->channel->band;
1418 wl->channel = channel;
1419
1420 /*
1421 * FIXME: the mac80211 should really provide a fixed rate
1422 * to use here. for now, just use the smallest possible rate
1423 * for the band as a fixed rate for association frames and
1424 * other control messages.
1425 */
1426 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1427 wl1271_set_band_rate(wl);
1428
1429 wl->basic_rate = wl1271_min_rate_get(wl);
1430 ret = wl1271_acx_rate_policies(wl);
1431 if (ret < 0)
1432 wl1271_warning("rate policy for update channel "
1433 "failed %d", ret);
1434
1435 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001436 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001437 if (ret < 0)
1438 wl1271_warning("cmd join to update channel "
1439 "failed %d", ret);
1440 }
1441 }
1442
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001443 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001444 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1445 if (ret < 0)
1446 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447 }
1448
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001449 /*
1450 * if mac80211 changes the PSM mode, make sure the mode is not
1451 * incorrectly changed after the pspoll failure active window.
1452 */
1453 if (changed & IEEE80211_CONF_CHANGE_PS)
1454 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1455
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001456 if (conf->flags & IEEE80211_CONF_PS &&
1457 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1458 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
1460 /*
1461 * We enter PSM only if we're already associated.
1462 * If we're not, we'll enter it when joining an SSID,
1463 * through the bss_info_changed() hook.
1464 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001465 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001466 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001467 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001468 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001469 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001471 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001472 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001474 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001476 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001477 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001478 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 }
1480
1481 if (conf->power_level != wl->power_level) {
1482 ret = wl1271_acx_tx_power(wl, conf->power_level);
1483 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001484 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485
1486 wl->power_level = conf->power_level;
1487 }
1488
1489out_sleep:
1490 wl1271_ps_elp_sleep(wl);
1491
1492out:
1493 mutex_unlock(&wl->mutex);
1494
1495 return ret;
1496}
1497
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001498struct wl1271_filter_params {
1499 bool enabled;
1500 int mc_list_length;
1501 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1502};
1503
Jiri Pirko22bedad32010-04-01 21:22:57 +00001504static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1505 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001506{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001507 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001508 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001509 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001510
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001511 if (unlikely(wl->state == WL1271_STATE_OFF))
1512 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001513
Juuso Oikarinen74441132009-10-13 12:47:53 +03001514 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001515 if (!fp) {
1516 wl1271_error("Out of memory setting filters.");
1517 return 0;
1518 }
1519
1520 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001521 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001522 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1523 fp->enabled = false;
1524 } else {
1525 fp->enabled = true;
1526 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001527 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001528 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001529 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001530 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001531 }
1532
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001533 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001534}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001536#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1537 FIF_ALLMULTI | \
1538 FIF_FCSFAIL | \
1539 FIF_BCN_PRBRESP_PROMISC | \
1540 FIF_CONTROL | \
1541 FIF_OTHER_BSS)
1542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1544 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001545 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001547 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001549 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001550
1551 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1552
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001553 mutex_lock(&wl->mutex);
1554
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001555 *total &= WL1271_SUPPORTED_FILTERS;
1556 changed &= WL1271_SUPPORTED_FILTERS;
1557
1558 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001559 goto out;
1560
1561 ret = wl1271_ps_elp_wakeup(wl, false);
1562 if (ret < 0)
1563 goto out;
1564
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001566 if (*total & FIF_ALLMULTI)
1567 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1568 else if (fp)
1569 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1570 fp->mc_list,
1571 fp->mc_list_length);
1572 if (ret < 0)
1573 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001575 /* determine, whether supported filter values have changed */
1576 if (changed == 0)
1577 goto out_sleep;
1578
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001579 /* configure filters */
1580 wl->filters = *total;
1581 wl1271_configure_filters(wl, 0);
1582
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001583 /* apply configured filters */
1584 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1585 if (ret < 0)
1586 goto out_sleep;
1587
1588out_sleep:
1589 wl1271_ps_elp_sleep(wl);
1590
1591out:
1592 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001593 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594}
1595
1596static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1597 struct ieee80211_vif *vif,
1598 struct ieee80211_sta *sta,
1599 struct ieee80211_key_conf *key_conf)
1600{
1601 struct wl1271 *wl = hw->priv;
1602 const u8 *addr;
1603 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001604 u32 tx_seq_32 = 0;
1605 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 u8 key_type;
1607
1608 static const u8 bcast_addr[ETH_ALEN] =
1609 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1610
1611 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1612
1613 addr = sta ? sta->addr : bcast_addr;
1614
1615 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1616 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1617 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001618 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 key_conf->keylen, key_conf->flags);
1620 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1621
1622 if (is_zero_ether_addr(addr)) {
1623 /* We dont support TX only encryption */
1624 ret = -EOPNOTSUPP;
1625 goto out;
1626 }
1627
1628 mutex_lock(&wl->mutex);
1629
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001630 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1631 ret = -EAGAIN;
1632 goto out_unlock;
1633 }
1634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635 ret = wl1271_ps_elp_wakeup(wl, false);
1636 if (ret < 0)
1637 goto out_unlock;
1638
Johannes Berg97359d12010-08-10 09:46:38 +02001639 switch (key_conf->cipher) {
1640 case WLAN_CIPHER_SUITE_WEP40:
1641 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642 key_type = KEY_WEP;
1643
1644 key_conf->hw_key_idx = key_conf->keyidx;
1645 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001646 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647 key_type = KEY_TKIP;
1648
1649 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001650 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1651 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001652 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001653 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 key_type = KEY_AES;
1655
1656 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001657 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1658 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001660 case WL1271_CIPHER_SUITE_GEM:
1661 key_type = KEY_GEM;
1662 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1663 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1664 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001666 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667
1668 ret = -EOPNOTSUPP;
1669 goto out_sleep;
1670 }
1671
1672 switch (cmd) {
1673 case SET_KEY:
1674 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1675 key_conf->keyidx, key_type,
1676 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001677 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001678 if (ret < 0) {
1679 wl1271_error("Could not add or replace key");
1680 goto out_sleep;
1681 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001682
1683 /* the default WEP key needs to be configured at least once */
1684 if (key_type == KEY_WEP) {
1685 ret = wl1271_cmd_set_default_wep_key(wl,
1686 wl->default_key);
1687 if (ret < 0)
1688 goto out_sleep;
1689 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690 break;
1691
1692 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001693 /* The wl1271 does not allow to remove unicast keys - they
1694 will be cleared automatically on next CMD_JOIN. Ignore the
1695 request silently, as we dont want the mac80211 to emit
1696 an error message. */
1697 if (!is_broadcast_ether_addr(addr))
1698 break;
1699
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1701 key_conf->keyidx, key_type,
1702 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001703 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704 if (ret < 0) {
1705 wl1271_error("Could not remove key");
1706 goto out_sleep;
1707 }
1708 break;
1709
1710 default:
1711 wl1271_error("Unsupported key cmd 0x%x", cmd);
1712 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001713 break;
1714 }
1715
1716out_sleep:
1717 wl1271_ps_elp_sleep(wl);
1718
1719out_unlock:
1720 mutex_unlock(&wl->mutex);
1721
1722out:
1723 return ret;
1724}
1725
1726static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001727 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728 struct cfg80211_scan_request *req)
1729{
1730 struct wl1271 *wl = hw->priv;
1731 int ret;
1732 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001733 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734
1735 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1736
1737 if (req->n_ssids) {
1738 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001739 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001740 }
1741
1742 mutex_lock(&wl->mutex);
1743
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001744 if (wl->state == WL1271_STATE_OFF) {
1745 /*
1746 * We cannot return -EBUSY here because cfg80211 will expect
1747 * a call to ieee80211_scan_completed if we do - in this case
1748 * there won't be any call.
1749 */
1750 ret = -EAGAIN;
1751 goto out;
1752 }
1753
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001754 ret = wl1271_ps_elp_wakeup(wl, false);
1755 if (ret < 0)
1756 goto out;
1757
Luciano Coelho5924f892010-08-04 03:46:22 +03001758 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759
1760 wl1271_ps_elp_sleep(wl);
1761
1762out:
1763 mutex_unlock(&wl->mutex);
1764
1765 return ret;
1766}
1767
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001768static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1769{
1770 struct wl1271 *wl = hw->priv;
1771 int ret = 0;
1772
1773 mutex_lock(&wl->mutex);
1774
1775 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1776 ret = -EAGAIN;
1777 goto out;
1778 }
1779
1780 ret = wl1271_ps_elp_wakeup(wl, false);
1781 if (ret < 0)
1782 goto out;
1783
1784 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1785 if (ret < 0)
1786 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1787
1788 wl1271_ps_elp_sleep(wl);
1789
1790out:
1791 mutex_unlock(&wl->mutex);
1792
1793 return ret;
1794}
1795
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1797{
1798 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001799 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800
1801 mutex_lock(&wl->mutex);
1802
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001803 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1804 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001805 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001806 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 ret = wl1271_ps_elp_wakeup(wl, false);
1809 if (ret < 0)
1810 goto out;
1811
1812 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1813 if (ret < 0)
1814 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1815
1816 wl1271_ps_elp_sleep(wl);
1817
1818out:
1819 mutex_unlock(&wl->mutex);
1820
1821 return ret;
1822}
1823
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001824static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
1825 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001826{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001827 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001828
1829 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001830 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001831 if (ptr[0] == WLAN_EID_SSID) {
1832 wl->ssid_len = ptr[1];
1833 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1834 return;
1835 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001836 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001837 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001838 wl1271_error("No SSID in IEs!\n");
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001839}
1840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1842 struct ieee80211_vif *vif,
1843 struct ieee80211_bss_conf *bss_conf,
1844 u32 changed)
1845{
1846 enum wl1271_cmd_ps_mode mode;
1847 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001848 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001849 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001850 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 int ret;
1852
1853 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1854
1855 mutex_lock(&wl->mutex);
1856
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001857 if (unlikely(wl->state == WL1271_STATE_OFF))
1858 goto out;
1859
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 ret = wl1271_ps_elp_wakeup(wl, false);
1861 if (ret < 0)
1862 goto out;
1863
Eliad Peller9ee82d52010-09-19 18:55:09 +02001864 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001865 (wl->bss_type == BSS_TYPE_IBSS)) {
1866 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1867 bss_conf->beacon_int);
1868
1869 wl->beacon_int = bss_conf->beacon_int;
1870 do_join = true;
1871 }
1872
Eliad Peller9ee82d52010-09-19 18:55:09 +02001873 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001874 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001875 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1876
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001877 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1878
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001879 if (beacon) {
1880 struct ieee80211_hdr *hdr;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001881 int ieoffset = offsetof(struct ieee80211_mgmt,
1882 u.beacon.variable);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001883
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001884 wl1271_ssid_set(wl, beacon, ieoffset);
1885
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001886 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1887 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001888 beacon->len, 0,
1889 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001890
1891 if (ret < 0) {
1892 dev_kfree_skb(beacon);
1893 goto out_sleep;
1894 }
1895
1896 hdr = (struct ieee80211_hdr *) beacon->data;
1897 hdr->frame_control = cpu_to_le16(
1898 IEEE80211_FTYPE_MGMT |
1899 IEEE80211_STYPE_PROBE_RESP);
1900
1901 ret = wl1271_cmd_template_set(wl,
1902 CMD_TEMPL_PROBE_RESPONSE,
1903 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001904 beacon->len, 0,
1905 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001906 dev_kfree_skb(beacon);
1907 if (ret < 0)
1908 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001909
1910 /* Need to update the SSID (for filtering etc) */
1911 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001912 }
1913 }
1914
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001915 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1916 (wl->bss_type == BSS_TYPE_IBSS)) {
1917 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1918 bss_conf->enable_beacon ? "enabled" : "disabled");
1919
1920 if (bss_conf->enable_beacon)
1921 wl->set_bss_type = BSS_TYPE_IBSS;
1922 else
1923 wl->set_bss_type = BSS_TYPE_STA_BSS;
1924 do_join = true;
1925 }
1926
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001927 if (changed & BSS_CHANGED_CQM) {
1928 bool enable = false;
1929 if (bss_conf->cqm_rssi_thold)
1930 enable = true;
1931 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1932 bss_conf->cqm_rssi_thold,
1933 bss_conf->cqm_rssi_hyst);
1934 if (ret < 0)
1935 goto out;
1936 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1937 }
1938
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001939 if ((changed & BSS_CHANGED_BSSID) &&
1940 /*
1941 * Now we know the correct bssid, so we send a new join command
1942 * and enable the BSSID filter
1943 */
1944 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001945 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001946
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001947 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001948 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001949 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001950
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001951 ret = wl1271_build_qos_null_data(wl);
1952 if (ret < 0)
1953 goto out_sleep;
1954
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001955 /* filter out all packets not from this BSSID */
1956 wl1271_configure_filters(wl, 0);
1957
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001958 /* Need to update the BSSID (for filtering etc) */
1959 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001960 }
1961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 if (changed & BSS_CHANGED_ASSOC) {
1963 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001964 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001965 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001967 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001969 wl->ps_poll_failures = 0;
1970
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001971 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001972 * use basic rates from AP, and determine lowest rate
1973 * to use with control frames.
1974 */
1975 rates = bss_conf->basic_rates;
1976 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1977 rates);
1978 wl->basic_rate = wl1271_min_rate_get(wl);
1979 ret = wl1271_acx_rate_policies(wl);
1980 if (ret < 0)
1981 goto out_sleep;
1982
1983 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001984 * with wl1271, we don't need to update the
1985 * beacon_int and dtim_period, because the firmware
1986 * updates it by itself when the first beacon is
1987 * received after a join.
1988 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1990 if (ret < 0)
1991 goto out_sleep;
1992
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001993 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001994 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001995 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001996 dev_kfree_skb(wl->probereq);
1997 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
1998 ieoffset = offsetof(struct ieee80211_mgmt,
1999 u.probe_req.variable);
2000 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002001
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002002 /* enable the connection monitoring feature */
2003 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 if (ret < 0)
2005 goto out_sleep;
2006
2007 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002008 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2009 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002011 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002012 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002013 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002014 if (ret < 0)
2015 goto out_sleep;
2016 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002017 } else {
2018 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002019 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002020 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002021 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002022
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002023 /* free probe-request template */
2024 dev_kfree_skb(wl->probereq);
2025 wl->probereq = NULL;
2026
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002027 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002028 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002029
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002030 /* revert back to minimum rates for the current band */
2031 wl1271_set_band_rate(wl);
2032 wl->basic_rate = wl1271_min_rate_get(wl);
2033 ret = wl1271_acx_rate_policies(wl);
2034 if (ret < 0)
2035 goto out_sleep;
2036
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002037 /* disable connection monitor features */
2038 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002039
2040 /* Disable the keep-alive feature */
2041 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002042 if (ret < 0)
2043 goto out_sleep;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002044
2045 /* restore the bssid filter and go to dummy bssid */
2046 wl1271_unjoin(wl);
2047 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002050 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 if (changed & BSS_CHANGED_ERP_SLOT) {
2053 if (bss_conf->use_short_slot)
2054 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2055 else
2056 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2057 if (ret < 0) {
2058 wl1271_warning("Set slot time failed %d", ret);
2059 goto out_sleep;
2060 }
2061 }
2062
2063 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2064 if (bss_conf->use_short_preamble)
2065 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2066 else
2067 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2068 }
2069
2070 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2071 if (bss_conf->use_cts_prot)
2072 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2073 else
2074 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2075 if (ret < 0) {
2076 wl1271_warning("Set ctsprotect failed %d", ret);
2077 goto out_sleep;
2078 }
2079 }
2080
Shahar Levi18357852010-10-13 16:09:41 +02002081 /*
2082 * Takes care of: New association with HT enable,
2083 * HT information change in beacon.
2084 */
2085 if (sta &&
2086 (changed & BSS_CHANGED_HT) &&
2087 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2088 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2089 if (ret < 0) {
2090 wl1271_warning("Set ht cap true failed %d", ret);
2091 goto out_sleep;
2092 }
2093 ret = wl1271_acx_set_ht_information(wl,
2094 bss_conf->ht_operation_mode);
2095 if (ret < 0) {
2096 wl1271_warning("Set ht information failed %d", ret);
2097 goto out_sleep;
2098 }
2099 }
2100 /*
2101 * Takes care of: New association without HT,
2102 * Disassociation.
2103 */
2104 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2105 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2106 if (ret < 0) {
2107 wl1271_warning("Set ht cap false failed %d", ret);
2108 goto out_sleep;
2109 }
2110 }
2111
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002112 if (changed & BSS_CHANGED_ARP_FILTER) {
2113 __be32 addr = bss_conf->arp_addr_list[0];
2114 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2115
Eliad Pellerc5312772010-12-09 11:31:27 +02002116 if (bss_conf->arp_addr_cnt == 1 &&
2117 bss_conf->arp_filter_enabled) {
2118 /*
2119 * The template should have been configured only upon
2120 * association. however, it seems that the correct ip
2121 * isn't being set (when sending), so we have to
2122 * reconfigure the template upon every ip change.
2123 */
2124 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2125 if (ret < 0) {
2126 wl1271_warning("build arp rsp failed: %d", ret);
2127 goto out_sleep;
2128 }
2129
2130 ret = wl1271_acx_arp_ip_filter(wl,
2131 (ACX_ARP_FILTER_ARP_FILTERING |
2132 ACX_ARP_FILTER_AUTO_ARP),
2133 addr);
2134 } else
2135 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002136
2137 if (ret < 0)
2138 goto out_sleep;
2139 }
2140
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002141 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002142 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002143 if (ret < 0) {
2144 wl1271_warning("cmd join failed %d", ret);
2145 goto out_sleep;
2146 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002147 }
2148
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149out_sleep:
2150 wl1271_ps_elp_sleep(wl);
2151
2152out:
2153 mutex_unlock(&wl->mutex);
2154}
2155
Kalle Valoc6999d82010-02-18 13:25:41 +02002156static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2157 const struct ieee80211_tx_queue_params *params)
2158{
2159 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002160 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002161 int ret;
2162
2163 mutex_lock(&wl->mutex);
2164
2165 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2166
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002167 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2168 ret = -EAGAIN;
2169 goto out;
2170 }
2171
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002172 ret = wl1271_ps_elp_wakeup(wl, false);
2173 if (ret < 0)
2174 goto out;
2175
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002176 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002177 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2178 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002179 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002180 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002181 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002182
Kalle Valo4695dc92010-03-18 12:26:38 +02002183 if (params->uapsd)
2184 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2185 else
2186 ps_scheme = CONF_PS_SCHEME_LEGACY;
2187
Kalle Valoc6999d82010-02-18 13:25:41 +02002188 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2189 CONF_CHANNEL_TYPE_EDCF,
2190 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002191 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002192 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002193 goto out_sleep;
2194
2195out_sleep:
2196 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002197
2198out:
2199 mutex_unlock(&wl->mutex);
2200
2201 return ret;
2202}
2203
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002204static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2205{
2206
2207 struct wl1271 *wl = hw->priv;
2208 u64 mactime = ULLONG_MAX;
2209 int ret;
2210
2211 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2212
2213 mutex_lock(&wl->mutex);
2214
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002215 if (unlikely(wl->state == WL1271_STATE_OFF))
2216 goto out;
2217
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002218 ret = wl1271_ps_elp_wakeup(wl, false);
2219 if (ret < 0)
2220 goto out;
2221
2222 ret = wl1271_acx_tsf_info(wl, &mactime);
2223 if (ret < 0)
2224 goto out_sleep;
2225
2226out_sleep:
2227 wl1271_ps_elp_sleep(wl);
2228
2229out:
2230 mutex_unlock(&wl->mutex);
2231 return mactime;
2232}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002233
John W. Linvilleece550d2010-07-28 16:41:06 -04002234static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2235 struct survey_info *survey)
2236{
2237 struct wl1271 *wl = hw->priv;
2238 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002239
John W. Linvilleece550d2010-07-28 16:41:06 -04002240 if (idx != 0)
2241 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002242
John W. Linvilleece550d2010-07-28 16:41:06 -04002243 survey->channel = conf->channel;
2244 survey->filled = SURVEY_INFO_NOISE_DBM;
2245 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002246
John W. Linvilleece550d2010-07-28 16:41:06 -04002247 return 0;
2248}
2249
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002250/* can't be const, mac80211 writes to this */
2251static struct ieee80211_rate wl1271_rates[] = {
2252 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002253 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2254 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002255 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002256 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2257 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2259 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002260 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2261 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2263 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002264 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2265 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2267 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002268 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2269 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002271 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2272 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002273 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002274 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2275 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002277 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2278 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002280 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2281 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002282 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002283 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2284 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002285 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002286 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2287 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002289 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2290 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291};
2292
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002293/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002294static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002295 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002296 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002297 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2298 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2299 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002300 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002301 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2302 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2303 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002304 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002305 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2306 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2307 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308};
2309
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002310/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002311static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002312 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002313 7, /* CONF_HW_RXTX_RATE_MCS7 */
2314 6, /* CONF_HW_RXTX_RATE_MCS6 */
2315 5, /* CONF_HW_RXTX_RATE_MCS5 */
2316 4, /* CONF_HW_RXTX_RATE_MCS4 */
2317 3, /* CONF_HW_RXTX_RATE_MCS3 */
2318 2, /* CONF_HW_RXTX_RATE_MCS2 */
2319 1, /* CONF_HW_RXTX_RATE_MCS1 */
2320 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002321
2322 11, /* CONF_HW_RXTX_RATE_54 */
2323 10, /* CONF_HW_RXTX_RATE_48 */
2324 9, /* CONF_HW_RXTX_RATE_36 */
2325 8, /* CONF_HW_RXTX_RATE_24 */
2326
2327 /* TI-specific rate */
2328 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2329
2330 7, /* CONF_HW_RXTX_RATE_18 */
2331 6, /* CONF_HW_RXTX_RATE_12 */
2332 3, /* CONF_HW_RXTX_RATE_11 */
2333 5, /* CONF_HW_RXTX_RATE_9 */
2334 4, /* CONF_HW_RXTX_RATE_6 */
2335 2, /* CONF_HW_RXTX_RATE_5_5 */
2336 1, /* CONF_HW_RXTX_RATE_2 */
2337 0 /* CONF_HW_RXTX_RATE_1 */
2338};
2339
Shahar Levie8b03a22010-10-13 16:09:39 +02002340/* 11n STA capabilities */
2341#define HW_RX_HIGHEST_RATE 72
2342
Shahar Levi00d20102010-11-08 11:20:10 +00002343#ifdef CONFIG_WL12XX_HT
2344#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002345 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2346 .ht_supported = true, \
2347 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2348 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2349 .mcs = { \
2350 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2351 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2352 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2353 }, \
2354}
Shahar Levi18357852010-10-13 16:09:41 +02002355#else
Shahar Levi00d20102010-11-08 11:20:10 +00002356#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002357 .ht_supported = false, \
2358}
2359#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361/* can't be const, mac80211 writes to this */
2362static struct ieee80211_supported_band wl1271_band_2ghz = {
2363 .channels = wl1271_channels,
2364 .n_channels = ARRAY_SIZE(wl1271_channels),
2365 .bitrates = wl1271_rates,
2366 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002367 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368};
2369
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002370/* 5 GHz data rates for WL1273 */
2371static struct ieee80211_rate wl1271_rates_5ghz[] = {
2372 { .bitrate = 60,
2373 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2374 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2375 { .bitrate = 90,
2376 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2377 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2378 { .bitrate = 120,
2379 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2380 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2381 { .bitrate = 180,
2382 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2383 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2384 { .bitrate = 240,
2385 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2386 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2387 { .bitrate = 360,
2388 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2389 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2390 { .bitrate = 480,
2391 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2392 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2393 { .bitrate = 540,
2394 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2395 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2396};
2397
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002398/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002399static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002400 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002401 { .hw_value = 8, .center_freq = 5040},
2402 { .hw_value = 9, .center_freq = 5045},
2403 { .hw_value = 11, .center_freq = 5055},
2404 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002405 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002406 { .hw_value = 34, .center_freq = 5170},
2407 { .hw_value = 36, .center_freq = 5180},
2408 { .hw_value = 38, .center_freq = 5190},
2409 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002410 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002411 { .hw_value = 44, .center_freq = 5220},
2412 { .hw_value = 46, .center_freq = 5230},
2413 { .hw_value = 48, .center_freq = 5240},
2414 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002415 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002416 { .hw_value = 60, .center_freq = 5300},
2417 { .hw_value = 64, .center_freq = 5320},
2418 { .hw_value = 100, .center_freq = 5500},
2419 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002420 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002421 { .hw_value = 112, .center_freq = 5560},
2422 { .hw_value = 116, .center_freq = 5580},
2423 { .hw_value = 120, .center_freq = 5600},
2424 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002425 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002426 { .hw_value = 132, .center_freq = 5660},
2427 { .hw_value = 136, .center_freq = 5680},
2428 { .hw_value = 140, .center_freq = 5700},
2429 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002430 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002431 { .hw_value = 157, .center_freq = 5785},
2432 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002433 { .hw_value = 165, .center_freq = 5825},
2434};
2435
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002436/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002437static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002438 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002439 7, /* CONF_HW_RXTX_RATE_MCS7 */
2440 6, /* CONF_HW_RXTX_RATE_MCS6 */
2441 5, /* CONF_HW_RXTX_RATE_MCS5 */
2442 4, /* CONF_HW_RXTX_RATE_MCS4 */
2443 3, /* CONF_HW_RXTX_RATE_MCS3 */
2444 2, /* CONF_HW_RXTX_RATE_MCS2 */
2445 1, /* CONF_HW_RXTX_RATE_MCS1 */
2446 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002447
2448 7, /* CONF_HW_RXTX_RATE_54 */
2449 6, /* CONF_HW_RXTX_RATE_48 */
2450 5, /* CONF_HW_RXTX_RATE_36 */
2451 4, /* CONF_HW_RXTX_RATE_24 */
2452
2453 /* TI-specific rate */
2454 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2455
2456 3, /* CONF_HW_RXTX_RATE_18 */
2457 2, /* CONF_HW_RXTX_RATE_12 */
2458 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2459 1, /* CONF_HW_RXTX_RATE_9 */
2460 0, /* CONF_HW_RXTX_RATE_6 */
2461 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2462 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2463 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2464};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002465
2466static struct ieee80211_supported_band wl1271_band_5ghz = {
2467 .channels = wl1271_channels_5ghz,
2468 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2469 .bitrates = wl1271_rates_5ghz,
2470 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002471 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002472};
2473
Tobias Klausera0ea9492010-05-20 10:38:11 +02002474static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002475 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2476 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2477};
2478
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002479static const struct ieee80211_ops wl1271_ops = {
2480 .start = wl1271_op_start,
2481 .stop = wl1271_op_stop,
2482 .add_interface = wl1271_op_add_interface,
2483 .remove_interface = wl1271_op_remove_interface,
2484 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002485 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002486 .configure_filter = wl1271_op_configure_filter,
2487 .tx = wl1271_op_tx,
2488 .set_key = wl1271_op_set_key,
2489 .hw_scan = wl1271_op_hw_scan,
2490 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002491 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002493 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002494 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002495 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002496 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002497};
2498
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002499
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002500u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002501{
2502 u8 idx;
2503
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002504 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002505
2506 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2507 wl1271_error("Illegal RX rate from HW: %d", rate);
2508 return 0;
2509 }
2510
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002511 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002512 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2513 wl1271_error("Unsupported RX rate from HW: %d", rate);
2514 return 0;
2515 }
2516
2517 return idx;
2518}
2519
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002520static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2521 struct device_attribute *attr,
2522 char *buf)
2523{
2524 struct wl1271 *wl = dev_get_drvdata(dev);
2525 ssize_t len;
2526
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002527 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002528
2529 mutex_lock(&wl->mutex);
2530 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2531 wl->sg_enabled);
2532 mutex_unlock(&wl->mutex);
2533
2534 return len;
2535
2536}
2537
2538static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2539 struct device_attribute *attr,
2540 const char *buf, size_t count)
2541{
2542 struct wl1271 *wl = dev_get_drvdata(dev);
2543 unsigned long res;
2544 int ret;
2545
2546 ret = strict_strtoul(buf, 10, &res);
2547
2548 if (ret < 0) {
2549 wl1271_warning("incorrect value written to bt_coex_mode");
2550 return count;
2551 }
2552
2553 mutex_lock(&wl->mutex);
2554
2555 res = !!res;
2556
2557 if (res == wl->sg_enabled)
2558 goto out;
2559
2560 wl->sg_enabled = res;
2561
2562 if (wl->state == WL1271_STATE_OFF)
2563 goto out;
2564
2565 ret = wl1271_ps_elp_wakeup(wl, false);
2566 if (ret < 0)
2567 goto out;
2568
2569 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2570 wl1271_ps_elp_sleep(wl);
2571
2572 out:
2573 mutex_unlock(&wl->mutex);
2574 return count;
2575}
2576
2577static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2578 wl1271_sysfs_show_bt_coex_state,
2579 wl1271_sysfs_store_bt_coex_state);
2580
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002581static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2582 struct device_attribute *attr,
2583 char *buf)
2584{
2585 struct wl1271 *wl = dev_get_drvdata(dev);
2586 ssize_t len;
2587
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002588 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002589
2590 mutex_lock(&wl->mutex);
2591 if (wl->hw_pg_ver >= 0)
2592 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2593 else
2594 len = snprintf(buf, len, "n/a\n");
2595 mutex_unlock(&wl->mutex);
2596
2597 return len;
2598}
2599
2600static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2601 wl1271_sysfs_show_hw_pg_ver, NULL);
2602
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002603int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002604{
2605 int ret;
2606
2607 if (wl->mac80211_registered)
2608 return 0;
2609
2610 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2611
2612 ret = ieee80211_register_hw(wl->hw);
2613 if (ret < 0) {
2614 wl1271_error("unable to register mac80211 hw: %d", ret);
2615 return ret;
2616 }
2617
2618 wl->mac80211_registered = true;
2619
Eliad Pellerd60080a2010-11-24 12:53:16 +02002620 wl1271_debugfs_init(wl);
2621
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002622 register_netdevice_notifier(&wl1271_dev_notifier);
2623
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002624 wl1271_notice("loaded");
2625
2626 return 0;
2627}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002628EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002629
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002630void wl1271_unregister_hw(struct wl1271 *wl)
2631{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002632 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002633 ieee80211_unregister_hw(wl->hw);
2634 wl->mac80211_registered = false;
2635
2636}
2637EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2638
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002639int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002641 static const u32 cipher_suites[] = {
2642 WLAN_CIPHER_SUITE_WEP40,
2643 WLAN_CIPHER_SUITE_WEP104,
2644 WLAN_CIPHER_SUITE_TKIP,
2645 WLAN_CIPHER_SUITE_CCMP,
2646 WL1271_CIPHER_SUITE_GEM,
2647 };
2648
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002649 /* The tx descriptor buffer and the TKIP space. */
2650 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2651 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002652
2653 /* unit us */
2654 /* FIXME: find a proper value */
2655 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002656 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002657
2658 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002659 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002660 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002661 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002662 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002663 IEEE80211_HW_CONNECTION_MONITOR |
2664 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002666 wl->hw->wiphy->cipher_suites = cipher_suites;
2667 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2668
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002669 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2670 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02002672 /*
2673 * Maximum length of elements in scanning probe request templates
2674 * should be the maximum length possible for a template, without
2675 * the IEEE80211 header of the template
2676 */
2677 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
2678 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002680 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002681
Kalle Valo12bd8942010-03-18 12:26:33 +02002682 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002683 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002684
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002685 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2686
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002687 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002688
2689 return 0;
2690}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002691EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002694
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002695struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002698 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002700 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002701 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702
2703 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2704 if (!hw) {
2705 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002706 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002707 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708 }
2709
Julia Lawall929ebd32010-05-15 23:16:39 +02002710 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002711 if (!plat_dev) {
2712 wl1271_error("could not allocate platform_device");
2713 ret = -ENOMEM;
2714 goto err_plat_alloc;
2715 }
2716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 wl = hw->priv;
2718 memset(wl, 0, sizeof(*wl));
2719
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002720 INIT_LIST_HEAD(&wl->list);
2721
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002723 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724
Juuso Oikarinen6742f552010-12-13 09:52:37 +02002725 for (i = 0; i < NUM_TX_QUEUES; i++)
2726 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002727
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002728 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002729 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002730 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2731 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2732 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2733 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002735 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737 wl->rx_counter = 0;
2738 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2739 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002740 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002741 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002742 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002743 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002744 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2745 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002746 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002747 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002748 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002749 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002750 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002751
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002752 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002753 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002754 wl->tx_frames[i] = NULL;
2755
2756 spin_lock_init(&wl->wl_lock);
2757
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 wl->state = WL1271_STATE_OFF;
2759 mutex_init(&wl->mutex);
2760
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002761 /* Apply default driver configuration. */
2762 wl1271_conf_init(wl);
2763
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002764 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2765 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2766 if (!wl->aggr_buf) {
2767 ret = -ENOMEM;
2768 goto err_hw;
2769 }
2770
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002771 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002772 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002773 if (ret) {
2774 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002775 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002776 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002777 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002778
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002779 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002780 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002781 if (ret < 0) {
2782 wl1271_error("failed to create sysfs file bt_coex_state");
2783 goto err_platform;
2784 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002785
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002786 /* Create sysfs file to get HW PG version */
2787 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2788 if (ret < 0) {
2789 wl1271_error("failed to create sysfs file hw_pg_ver");
2790 goto err_bt_coex_state;
2791 }
2792
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002793 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002794
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002795err_bt_coex_state:
2796 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2797
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002798err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002799 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002800
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002801err_aggr:
2802 free_pages((unsigned long)wl->aggr_buf, order);
2803
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002804err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002805 wl1271_debugfs_exit(wl);
2806 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002807
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002808err_plat_alloc:
2809 ieee80211_free_hw(hw);
2810
2811err_hw_alloc:
2812
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002813 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002814}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002815EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002816
2817int wl1271_free_hw(struct wl1271 *wl)
2818{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002819 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002820 free_pages((unsigned long)wl->aggr_buf,
2821 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002822 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002823
2824 wl1271_debugfs_exit(wl);
2825
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002826 vfree(wl->fw);
2827 wl->fw = NULL;
2828 kfree(wl->nvs);
2829 wl->nvs = NULL;
2830
2831 kfree(wl->fw_status);
2832 kfree(wl->tx_res_if);
2833
2834 ieee80211_free_hw(wl->hw);
2835
2836 return 0;
2837}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002838EXPORT_SYMBOL_GPL(wl1271_free_hw);
2839
Eliad Peller17c17552010-12-12 12:15:35 +02002840u32 wl12xx_debug_level;
2841EXPORT_SYMBOL_GPL(wl12xx_debug_level);
2842module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
2843MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
2844
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002845MODULE_LICENSE("GPL");
2846MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2847MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");