blob: 788959a5f0de2471124d64787c01245261216754 [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,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_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,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
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 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
194
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
259 .psm_entry_nullfunc_retries = 3,
260 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300261 .keep_alive_interval = 55000,
262 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200264 .itrim = {
265 .enable = false,
266 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200267 },
268 .pm_config = {
269 .host_clk_settling_time = 5000,
270 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300271 },
272 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300273 .trigger_pacing = 1,
274 .avg_weight_rssi_beacon = 20,
275 .avg_weight_rssi_data = 10,
276 .avg_weight_snr_beacon = 20,
277 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200278 },
279 .scan = {
280 .min_dwell_time_active = 7500,
281 .max_dwell_time_active = 30000,
282 .min_dwell_time_passive = 30000,
283 .max_dwell_time_passive = 60000,
284 .num_probe_reqs = 2,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300296};
297
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200298static void __wl1271_op_remove_interface(struct wl1271 *wl);
299
300
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200301static void wl1271_device_release(struct device *dev)
302{
303
304}
305
306static struct platform_device wl1271_device = {
307 .name = "wl1271",
308 .id = -1,
309
310 /* device model insists to have a release function */
311 .dev = {
312 .release = wl1271_device_release,
313 },
314};
315
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300316static LIST_HEAD(wl_list);
317
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300318static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
319 void *arg)
320{
321 struct net_device *dev = arg;
322 struct wireless_dev *wdev;
323 struct wiphy *wiphy;
324 struct ieee80211_hw *hw;
325 struct wl1271 *wl;
326 struct wl1271 *wl_temp;
327 int ret = 0;
328
329 /* Check that this notification is for us. */
330 if (what != NETDEV_CHANGE)
331 return NOTIFY_DONE;
332
333 wdev = dev->ieee80211_ptr;
334 if (wdev == NULL)
335 return NOTIFY_DONE;
336
337 wiphy = wdev->wiphy;
338 if (wiphy == NULL)
339 return NOTIFY_DONE;
340
341 hw = wiphy_priv(wiphy);
342 if (hw == NULL)
343 return NOTIFY_DONE;
344
345 wl_temp = hw->priv;
346 list_for_each_entry(wl, &wl_list, list) {
347 if (wl == wl_temp)
348 break;
349 }
350 if (wl != wl_temp)
351 return NOTIFY_DONE;
352
353 mutex_lock(&wl->mutex);
354
355 if (wl->state == WL1271_STATE_OFF)
356 goto out;
357
358 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
359 goto out;
360
361 ret = wl1271_ps_elp_wakeup(wl, false);
362 if (ret < 0)
363 goto out;
364
365 if ((dev->operstate == IF_OPER_UP) &&
366 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
367 wl1271_cmd_set_sta_state(wl);
368 wl1271_info("Association completed.");
369 }
370
371 wl1271_ps_elp_sleep(wl);
372
373out:
374 mutex_unlock(&wl->mutex);
375
376 return NOTIFY_OK;
377}
378
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100379static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200380 struct regulatory_request *request)
381{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100382 struct ieee80211_supported_band *band;
383 struct ieee80211_channel *ch;
384 int i;
385
386 band = wiphy->bands[IEEE80211_BAND_5GHZ];
387 for (i = 0; i < band->n_channels; i++) {
388 ch = &band->channels[i];
389 if (ch->flags & IEEE80211_CHAN_DISABLED)
390 continue;
391
392 if (ch->flags & IEEE80211_CHAN_RADAR)
393 ch->flags |= IEEE80211_CHAN_NO_IBSS |
394 IEEE80211_CHAN_PASSIVE_SCAN;
395
396 }
397
398 return 0;
399}
400
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300401static void wl1271_conf_init(struct wl1271 *wl)
402{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300403
404 /*
405 * This function applies the default configuration to the driver. This
406 * function is invoked upon driver load (spi probe.)
407 *
408 * The configuration is stored in a run-time structure in order to
409 * facilitate for run-time adjustment of any of the parameters. Making
410 * changes to the configuration structure will apply the new values on
411 * the next interface up (wl1271_op_start.)
412 */
413
414 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300415 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300416}
417
418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419static int wl1271_plt_init(struct wl1271 *wl)
420{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200421 struct conf_tx_ac_category *conf_ac;
422 struct conf_tx_tid *conf_tid;
423 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200425 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200426 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200427 return ret;
428
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200429 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200430 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200431 return ret;
432
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200433 ret = wl1271_cmd_ext_radio_parms(wl);
434 if (ret < 0)
435 return ret;
436
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 ret = wl1271_init_templates_config(wl);
438 if (ret < 0)
439 return ret;
440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 ret = wl1271_acx_init_mem_config(wl);
442 if (ret < 0)
443 return ret;
444
Luciano Coelho12419cc2010-02-18 13:25:44 +0200445 /* PHY layer config */
446 ret = wl1271_init_phy_config(wl);
447 if (ret < 0)
448 goto out_free_memmap;
449
450 ret = wl1271_acx_dco_itrim_params(wl);
451 if (ret < 0)
452 goto out_free_memmap;
453
454 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200455 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200456 if (ret < 0)
457 goto out_free_memmap;
458
459 /* Bluetooth WLAN coexistence */
460 ret = wl1271_init_pta(wl);
461 if (ret < 0)
462 goto out_free_memmap;
463
464 /* Energy detection */
465 ret = wl1271_init_energy_detection(wl);
466 if (ret < 0)
467 goto out_free_memmap;
468
469 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100470 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200471 if (ret < 0)
472 goto out_free_memmap;
473
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200474 /* Default TID/AC configuration */
475 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200476 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200477 conf_ac = &wl->conf.tx.ac_conf[i];
478 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
479 conf_ac->cw_max, conf_ac->aifsn,
480 conf_ac->tx_op_limit);
481 if (ret < 0)
482 goto out_free_memmap;
483
Luciano Coelho12419cc2010-02-18 13:25:44 +0200484 conf_tid = &wl->conf.tx.tid_conf[i];
485 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
486 conf_tid->channel_type,
487 conf_tid->tsid,
488 conf_tid->ps_scheme,
489 conf_tid->ack_policy,
490 conf_tid->apsd_conf[0],
491 conf_tid->apsd_conf[1]);
492 if (ret < 0)
493 goto out_free_memmap;
494 }
495
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200497 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200499 goto out_free_memmap;
500
501 /* Configure for CAM power saving (ie. always active) */
502 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
503 if (ret < 0)
504 goto out_free_memmap;
505
506 /* configure PM */
507 ret = wl1271_acx_pm_config(wl);
508 if (ret < 0)
509 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
511 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200512
513 out_free_memmap:
514 kfree(wl->target_mem_map);
515 wl->target_mem_map = NULL;
516
517 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518}
519
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300520static void wl1271_fw_status(struct wl1271 *wl,
521 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300522{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200523 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524 u32 total = 0;
525 int i;
526
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200527 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528
529 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
530 "drv_rx_counter = %d, tx_results_counter = %d)",
531 status->intr,
532 status->fw_rx_counter,
533 status->drv_rx_counter,
534 status->tx_results_counter);
535
536 /* update number of available TX blocks */
537 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300538 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
539 wl->tx_blocks_freed[i];
540
541 wl->tx_blocks_freed[i] =
542 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 wl->tx_blocks_available += cnt;
544 total += cnt;
545 }
546
Ido Yariva5225502010-10-12 14:49:10 +0200547 /* if more blocks are available now, tx work can be scheduled */
548 if (total)
549 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300550
551 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200552 getnstimeofday(&ts);
553 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
554 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555}
556
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200557#define WL1271_IRQ_MAX_LOOPS 10
558
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559static void wl1271_irq_work(struct work_struct *work)
560{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300562 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200563 int loopcount = WL1271_IRQ_MAX_LOOPS;
564 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565 struct wl1271 *wl =
566 container_of(work, struct wl1271, irq_work);
567
568 mutex_lock(&wl->mutex);
569
570 wl1271_debug(DEBUG_IRQ, "IRQ work");
571
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200572 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300573 goto out;
574
575 ret = wl1271_ps_elp_wakeup(wl, true);
576 if (ret < 0)
577 goto out;
578
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200579 spin_lock_irqsave(&wl->wl_lock, flags);
580 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
581 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
582 spin_unlock_irqrestore(&wl->wl_lock, flags);
583 loopcount--;
584
585 wl1271_fw_status(wl, wl->fw_status);
586 intr = le32_to_cpu(wl->fw_status->intr);
587 if (!intr) {
588 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200589 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200590 continue;
591 }
592
593 intr &= WL1271_INTR_MASK;
594
Eliad Pellerccc83b02010-10-27 14:09:57 +0200595 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
596 wl1271_error("watchdog interrupt received! "
597 "starting recovery.");
598 ieee80211_queue_work(wl->hw, &wl->recovery_work);
599
600 /* restarting the chip. ignore any other interrupt. */
601 goto out;
602 }
603
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200604 if (intr & WL1271_ACX_INTR_DATA) {
605 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
606
607 /* check for tx results */
608 if (wl->fw_status->tx_results_counter !=
609 (wl->tx_results_count & 0xff))
610 wl1271_tx_complete(wl);
611
Ido Yariva5225502010-10-12 14:49:10 +0200612 /* Check if any tx blocks were freed */
613 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200614 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200615 /*
616 * In order to avoid starvation of the TX path,
617 * call the work function directly.
618 */
619 wl1271_tx_work_locked(wl);
620 }
621
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200622 wl1271_rx(wl, wl->fw_status);
623 }
624
625 if (intr & WL1271_ACX_INTR_EVENT_A) {
626 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
627 wl1271_event_handle(wl, 0);
628 }
629
630 if (intr & WL1271_ACX_INTR_EVENT_B) {
631 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
632 wl1271_event_handle(wl, 1);
633 }
634
635 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
636 wl1271_debug(DEBUG_IRQ,
637 "WL1271_ACX_INTR_INIT_COMPLETE");
638
639 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
640 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
641
642 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300643 }
644
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200645 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
646 ieee80211_queue_work(wl->hw, &wl->irq_work);
647 else
648 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
649 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 wl1271_ps_elp_sleep(wl);
652
653out:
654 mutex_unlock(&wl->mutex);
655}
656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657static int wl1271_fetch_firmware(struct wl1271 *wl)
658{
659 const struct firmware *fw;
660 int ret;
661
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200662 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663
664 if (ret < 0) {
665 wl1271_error("could not get firmware: %d", ret);
666 return ret;
667 }
668
669 if (fw->size % 4) {
670 wl1271_error("firmware size is not multiple of 32 bits: %zu",
671 fw->size);
672 ret = -EILSEQ;
673 goto out;
674 }
675
676 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300677 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678
679 if (!wl->fw) {
680 wl1271_error("could not allocate memory for the firmware");
681 ret = -ENOMEM;
682 goto out;
683 }
684
685 memcpy(wl->fw, fw->data, wl->fw_len);
686
687 ret = 0;
688
689out:
690 release_firmware(fw);
691
692 return ret;
693}
694
695static int wl1271_fetch_nvs(struct wl1271 *wl)
696{
697 const struct firmware *fw;
698 int ret;
699
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200700 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701
702 if (ret < 0) {
703 wl1271_error("could not get nvs file: %d", ret);
704 return ret;
705 }
706
Julia Lawall929ebd32010-05-15 23:16:39 +0200707 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708
709 if (!wl->nvs) {
710 wl1271_error("could not allocate memory for the nvs file");
711 ret = -ENOMEM;
712 goto out;
713 }
714
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200715 wl->nvs_len = fw->size;
716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717out:
718 release_firmware(fw);
719
720 return ret;
721}
722
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200723static void wl1271_recovery_work(struct work_struct *work)
724{
725 struct wl1271 *wl =
726 container_of(work, struct wl1271, recovery_work);
727
728 mutex_lock(&wl->mutex);
729
730 if (wl->state != WL1271_STATE_ON)
731 goto out;
732
733 wl1271_info("Hardware recovery in progress.");
734
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200735 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
736 ieee80211_connection_loss(wl->vif);
737
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200738 /* reboot the chipset */
739 __wl1271_op_remove_interface(wl);
740 ieee80211_restart_hw(wl->hw);
741
742out:
743 mutex_unlock(&wl->mutex);
744}
745
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746static void wl1271_fw_wakeup(struct wl1271 *wl)
747{
748 u32 elp_reg;
749
750 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300751 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752}
753
754static int wl1271_setup(struct wl1271 *wl)
755{
756 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
757 if (!wl->fw_status)
758 return -ENOMEM;
759
760 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
761 if (!wl->tx_res_if) {
762 kfree(wl->fw_status);
763 return -ENOMEM;
764 }
765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766 return 0;
767}
768
769static int wl1271_chip_wakeup(struct wl1271 *wl)
770{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300771 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772 int ret = 0;
773
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200774 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200775 ret = wl1271_power_on(wl);
776 if (ret < 0)
777 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200779 wl1271_io_reset(wl);
780 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781
782 /* We don't need a real memory partition here, because we only want
783 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300784 memset(&partition, 0, sizeof(partition));
785 partition.reg.start = REGISTERS_BASE;
786 partition.reg.size = REGISTERS_DOWN_SIZE;
787 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
789 /* ELP module wake up */
790 wl1271_fw_wakeup(wl);
791
792 /* whal_FwCtrl_BootSm() */
793
794 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200795 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796
797 /* 1. check if chip id is valid */
798
799 switch (wl->chip.id) {
800 case CHIP_ID_1271_PG10:
801 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
802 wl->chip.id);
803
804 ret = wl1271_setup(wl);
805 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200806 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807 break;
808 case CHIP_ID_1271_PG20:
809 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
810 wl->chip.id);
811
812 ret = wl1271_setup(wl);
813 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200814 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 break;
816 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200817 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200819 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820 }
821
822 if (wl->fw == NULL) {
823 ret = wl1271_fetch_firmware(wl);
824 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200825 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 }
827
828 /* No NVS from netlink, try to get it from the filesystem */
829 if (wl->nvs == NULL) {
830 ret = wl1271_fetch_nvs(wl);
831 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200832 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833 }
834
835out:
836 return ret;
837}
838
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839int wl1271_plt_start(struct wl1271 *wl)
840{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200841 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 int ret;
843
844 mutex_lock(&wl->mutex);
845
846 wl1271_notice("power up");
847
848 if (wl->state != WL1271_STATE_OFF) {
849 wl1271_error("cannot go into PLT state because not "
850 "in off state: %d", wl->state);
851 ret = -EBUSY;
852 goto out;
853 }
854
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200855 while (retries) {
856 retries--;
857 ret = wl1271_chip_wakeup(wl);
858 if (ret < 0)
859 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200861 ret = wl1271_boot(wl);
862 if (ret < 0)
863 goto power_off;
864
865 ret = wl1271_plt_init(wl);
866 if (ret < 0)
867 goto irq_disable;
868
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200869 wl->state = WL1271_STATE_PLT;
870 wl1271_notice("firmware booted in PLT mode (%s)",
871 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872 goto out;
873
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200874irq_disable:
875 wl1271_disable_interrupts(wl);
876 mutex_unlock(&wl->mutex);
877 /* Unlocking the mutex in the middle of handling is
878 inherently unsafe. In this case we deem it safe to do,
879 because we need to let any possibly pending IRQ out of
880 the system (and while we are WL1271_STATE_OFF the IRQ
881 work function will not do anything.) Also, any other
882 possible concurrent operations will fail due to the
883 current state, hence the wl1271 struct should be safe. */
884 cancel_work_sync(&wl->irq_work);
885 mutex_lock(&wl->mutex);
886power_off:
887 wl1271_power_off(wl);
888 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200890 wl1271_error("firmware boot in PLT mode failed despite %d retries",
891 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892out:
893 mutex_unlock(&wl->mutex);
894
895 return ret;
896}
897
898int wl1271_plt_stop(struct wl1271 *wl)
899{
900 int ret = 0;
901
902 mutex_lock(&wl->mutex);
903
904 wl1271_notice("power down");
905
906 if (wl->state != WL1271_STATE_PLT) {
907 wl1271_error("cannot power down because not in PLT "
908 "state: %d", wl->state);
909 ret = -EBUSY;
910 goto out;
911 }
912
913 wl1271_disable_interrupts(wl);
914 wl1271_power_off(wl);
915
916 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300917 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918
919out:
920 mutex_unlock(&wl->mutex);
921
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200922 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200923 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 return ret;
926}
927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
929{
930 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200931 struct ieee80211_conf *conf = &hw->conf;
932 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
933 struct ieee80211_sta *sta = txinfo->control.sta;
934 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200935 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
Shahar Levi18357852010-10-13 16:09:41 +0200937 /*
938 * peek into the rates configured in the STA entry.
939 * The rates set after connection stage, The first block only BG sets:
940 * the compare is for bit 0-16 of sta_rate_set. The second block add
941 * HT rates in case of HT supported.
942 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200943 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200944 if (sta &&
945 (sta->supp_rates[conf->channel->band] !=
946 (wl->sta_rate_set & HW_BG_RATES_MASK))) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200947 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
948 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
949 }
Shahar Levi18357852010-10-13 16:09:41 +0200950
Shahar Levi00d20102010-11-08 11:20:10 +0000951#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200952 if (sta &&
953 sta->ht_cap.ht_supported &&
954 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
955 sta->ht_cap.mcs.rx_mask[0])) {
956 /* Clean MCS bits before setting them */
957 wl->sta_rate_set &= HW_BG_RATES_MASK;
958 wl->sta_rate_set |=
959 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
960 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
961 }
962#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200963 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200964 spin_unlock_irqrestore(&wl->wl_lock, flags);
965
966 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200967 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
968 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
970 /*
971 * The chip specific setup must run before the first TX packet -
972 * before that, the tx_work will not be initialized!
973 */
974
Ido Yariva5225502010-10-12 14:49:10 +0200975 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
976 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977
978 /*
979 * The workqueue is slow to process the tx_queue and we need stop
980 * the queue here, otherwise the queue will get too long.
981 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200982 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200983 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200985 spin_lock_irqsave(&wl->wl_lock, flags);
986 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200987 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200988 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 }
990
991 return NETDEV_TX_OK;
992}
993
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300994static struct notifier_block wl1271_dev_notifier = {
995 .notifier_call = wl1271_dev_notify,
996};
997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998static int wl1271_op_start(struct ieee80211_hw *hw)
999{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001000 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1001
1002 /*
1003 * We have to delay the booting of the hardware because
1004 * we need to know the local MAC address before downloading and
1005 * initializing the firmware. The MAC address cannot be changed
1006 * after boot, and without the proper MAC address, the firmware
1007 * will not function properly.
1008 *
1009 * The MAC address is first known when the corresponding interface
1010 * is added. That is where we will initialize the hardware.
1011 */
1012
1013 return 0;
1014}
1015
1016static void wl1271_op_stop(struct ieee80211_hw *hw)
1017{
1018 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1019}
1020
1021static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1022 struct ieee80211_vif *vif)
1023{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001025 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001026 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001028 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001030 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1031 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032
1033 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001034 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001035 wl1271_debug(DEBUG_MAC80211,
1036 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001037 ret = -EBUSY;
1038 goto out;
1039 }
1040
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001041 switch (vif->type) {
1042 case NL80211_IFTYPE_STATION:
1043 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001044 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001045 break;
1046 case NL80211_IFTYPE_ADHOC:
1047 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001048 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001049 break;
1050 default:
1051 ret = -EOPNOTSUPP;
1052 goto out;
1053 }
1054
1055 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (wl->state != WL1271_STATE_OFF) {
1058 wl1271_error("cannot start because not in off state: %d",
1059 wl->state);
1060 ret = -EBUSY;
1061 goto out;
1062 }
1063
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001064 while (retries) {
1065 retries--;
1066 ret = wl1271_chip_wakeup(wl);
1067 if (ret < 0)
1068 goto power_off;
1069
1070 ret = wl1271_boot(wl);
1071 if (ret < 0)
1072 goto power_off;
1073
1074 ret = wl1271_hw_init(wl);
1075 if (ret < 0)
1076 goto irq_disable;
1077
Eliad Peller71125ab2010-10-28 21:46:43 +02001078 booted = true;
1079 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001081irq_disable:
1082 wl1271_disable_interrupts(wl);
1083 mutex_unlock(&wl->mutex);
1084 /* Unlocking the mutex in the middle of handling is
1085 inherently unsafe. In this case we deem it safe to do,
1086 because we need to let any possibly pending IRQ out of
1087 the system (and while we are WL1271_STATE_OFF the IRQ
1088 work function will not do anything.) Also, any other
1089 possible concurrent operations will fail due to the
1090 current state, hence the wl1271 struct should be safe. */
1091 cancel_work_sync(&wl->irq_work);
1092 mutex_lock(&wl->mutex);
1093power_off:
1094 wl1271_power_off(wl);
1095 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096
Eliad Peller71125ab2010-10-28 21:46:43 +02001097 if (!booted) {
1098 wl1271_error("firmware boot failed despite %d retries",
1099 WL1271_BOOT_RETRIES);
1100 goto out;
1101 }
1102
1103 wl->vif = vif;
1104 wl->state = WL1271_STATE_ON;
1105 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1106
1107 /* update hw/fw version info in wiphy struct */
1108 wiphy->hw_version = wl->chip.id;
1109 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1110 sizeof(wiphy->fw_version));
1111
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001112 /*
1113 * Now we know if 11a is supported (info from the NVS), so disable
1114 * 11a channels if not supported
1115 */
1116 if (!wl->enable_11a)
1117 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1118
1119 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1120 wl->enable_11a ? "" : "not ");
1121
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001122out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 mutex_unlock(&wl->mutex);
1124
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001125 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001126 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128 return ret;
1129}
1130
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001131static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133 int i;
1134
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001135 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001137 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001139 list_del(&wl->list);
1140
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 WARN_ON(wl->state != WL1271_STATE_ON);
1142
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001143 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001144 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001145 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001146
Luciano Coelho08688d62010-07-08 17:50:07 +03001147 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001148 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1149 kfree(wl->scan.scanned_ch);
1150 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001151 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001152 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 }
1154
1155 wl->state = WL1271_STATE_OFF;
1156
1157 wl1271_disable_interrupts(wl);
1158
1159 mutex_unlock(&wl->mutex);
1160
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001161 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162 cancel_work_sync(&wl->irq_work);
1163 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001164 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001165 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166
1167 mutex_lock(&wl->mutex);
1168
1169 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001170 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001171 wl1271_power_off(wl);
1172
1173 memset(wl->bssid, 0, ETH_ALEN);
1174 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1175 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001177 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001178 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179
1180 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001181 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1183 wl->tx_blocks_available = 0;
1184 wl->tx_results_count = 0;
1185 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001186 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001187 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188 wl->time_offset = 0;
1189 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001190 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1191 wl->sta_rate_set = 0;
1192 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001193 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001194 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196 for (i = 0; i < NUM_TX_QUEUES; i++)
1197 wl->tx_blocks_freed[i] = 0;
1198
1199 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001200
1201 kfree(wl->fw_status);
1202 wl->fw_status = NULL;
1203 kfree(wl->tx_res_if);
1204 wl->tx_res_if = NULL;
1205 kfree(wl->target_mem_map);
1206 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001207}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001208
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001209static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1210 struct ieee80211_vif *vif)
1211{
1212 struct wl1271 *wl = hw->priv;
1213
1214 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001215 /*
1216 * wl->vif can be null here if someone shuts down the interface
1217 * just when hardware recovery has been started.
1218 */
1219 if (wl->vif) {
1220 WARN_ON(wl->vif != vif);
1221 __wl1271_op_remove_interface(wl);
1222 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001223
Juuso Oikarinen67353292010-11-18 15:19:02 +02001224 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001225 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226}
1227
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001228static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1229{
1230 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1231 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1232
1233 /* combine requested filters with current filter config */
1234 filters = wl->filters | filters;
1235
1236 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1237
1238 if (filters & FIF_PROMISC_IN_BSS) {
1239 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1240 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1241 wl->rx_config |= CFG_BSSID_FILTER_EN;
1242 }
1243 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1244 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1245 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1246 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1247 }
1248 if (filters & FIF_OTHER_BSS) {
1249 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1250 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1251 }
1252 if (filters & FIF_CONTROL) {
1253 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1254 wl->rx_filter |= CFG_RX_CTL_EN;
1255 }
1256 if (filters & FIF_FCSFAIL) {
1257 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1258 wl->rx_filter |= CFG_RX_FCS_ERROR;
1259 }
1260}
1261
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001262static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001263{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001264 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001265 /* we need to use a dummy BSSID for now */
1266 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1267 0xad, 0xbe, 0xef };
1268
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001269 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1270
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001271 /* pass through frames from all BSS */
1272 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1273
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001274 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001275 if (ret < 0)
1276 goto out;
1277
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001278 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001279
1280out:
1281 return ret;
1282}
1283
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001284static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001285{
1286 int ret;
1287
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001288 /*
1289 * One of the side effects of the JOIN command is that is clears
1290 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1291 * to a WPA/WPA2 access point will therefore kill the data-path.
1292 * Currently there is no supported scenario for JOIN during
1293 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1294 * must be handled somehow.
1295 *
1296 */
1297 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1298 wl1271_info("JOIN while associated.");
1299
1300 if (set_assoc)
1301 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1302
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001303 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1304 if (ret < 0)
1305 goto out;
1306
1307 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1308
1309 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1310 goto out;
1311
1312 /*
1313 * The join command disable the keep-alive mode, shut down its process,
1314 * and also clear the template config, so we need to reset it all after
1315 * the join. The acx_aid starts the keep-alive process, and the order
1316 * of the commands below is relevant.
1317 */
1318 ret = wl1271_acx_keep_alive_mode(wl, true);
1319 if (ret < 0)
1320 goto out;
1321
1322 ret = wl1271_acx_aid(wl, wl->aid);
1323 if (ret < 0)
1324 goto out;
1325
1326 ret = wl1271_cmd_build_klv_null_data(wl);
1327 if (ret < 0)
1328 goto out;
1329
1330 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1331 ACX_KEEP_ALIVE_TPL_VALID);
1332 if (ret < 0)
1333 goto out;
1334
1335out:
1336 return ret;
1337}
1338
1339static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001340{
1341 int ret;
1342
1343 /* to stop listening to a channel, we disconnect */
1344 ret = wl1271_cmd_disconnect(wl);
1345 if (ret < 0)
1346 goto out;
1347
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001348 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001349 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001350
1351 /* stop filterting packets based on bssid */
1352 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001353
1354out:
1355 return ret;
1356}
1357
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001358static void wl1271_set_band_rate(struct wl1271 *wl)
1359{
1360 if (wl->band == IEEE80211_BAND_2GHZ)
1361 wl->basic_rate_set = wl->conf.tx.basic_rate;
1362 else
1363 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1364}
1365
1366static u32 wl1271_min_rate_get(struct wl1271 *wl)
1367{
1368 int i;
1369 u32 rate = 0;
1370
1371 if (!wl->basic_rate_set) {
1372 WARN_ON(1);
1373 wl->basic_rate_set = wl->conf.tx.basic_rate;
1374 }
1375
1376 for (i = 0; !rate; i++) {
1377 if ((wl->basic_rate_set >> i) & 0x1)
1378 rate = 1 << i;
1379 }
1380
1381 return rate;
1382}
1383
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001384static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1385{
1386 int ret;
1387
1388 if (idle) {
1389 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1390 ret = wl1271_unjoin(wl);
1391 if (ret < 0)
1392 goto out;
1393 }
1394 wl->rate_set = wl1271_min_rate_get(wl);
1395 wl->sta_rate_set = 0;
1396 ret = wl1271_acx_rate_policies(wl);
1397 if (ret < 0)
1398 goto out;
1399 ret = wl1271_acx_keep_alive_config(
1400 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1401 ACX_KEEP_ALIVE_TPL_INVALID);
1402 if (ret < 0)
1403 goto out;
1404 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1405 } else {
1406 /* increment the session counter */
1407 wl->session_counter++;
1408 if (wl->session_counter >= SESSION_COUNTER_MAX)
1409 wl->session_counter = 0;
1410 ret = wl1271_dummy_join(wl);
1411 if (ret < 0)
1412 goto out;
1413 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1414 }
1415
1416out:
1417 return ret;
1418}
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1421{
1422 struct wl1271 *wl = hw->priv;
1423 struct ieee80211_conf *conf = &hw->conf;
1424 int channel, ret = 0;
1425
1426 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1427
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001428 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 channel,
1430 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001431 conf->power_level,
1432 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001434 /*
1435 * mac80211 will go to idle nearly immediately after transmitting some
1436 * frames, such as the deauth. To make sure those frames reach the air,
1437 * wait here until the TX queue is fully flushed.
1438 */
1439 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1440 (conf->flags & IEEE80211_CONF_IDLE))
1441 wl1271_tx_flush(wl);
1442
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 mutex_lock(&wl->mutex);
1444
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001445 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1446 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001447 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001448 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 ret = wl1271_ps_elp_wakeup(wl, false);
1451 if (ret < 0)
1452 goto out;
1453
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001454 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001455 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1456 ((wl->band != conf->channel->band) ||
1457 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001458 wl->band = conf->channel->band;
1459 wl->channel = channel;
1460
1461 /*
1462 * FIXME: the mac80211 should really provide a fixed rate
1463 * to use here. for now, just use the smallest possible rate
1464 * for the band as a fixed rate for association frames and
1465 * other control messages.
1466 */
1467 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1468 wl1271_set_band_rate(wl);
1469
1470 wl->basic_rate = wl1271_min_rate_get(wl);
1471 ret = wl1271_acx_rate_policies(wl);
1472 if (ret < 0)
1473 wl1271_warning("rate policy for update channel "
1474 "failed %d", ret);
1475
1476 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001477 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001478 if (ret < 0)
1479 wl1271_warning("cmd join to update channel "
1480 "failed %d", ret);
1481 }
1482 }
1483
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001484 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001485 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1486 if (ret < 0)
1487 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488 }
1489
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001490 /*
1491 * if mac80211 changes the PSM mode, make sure the mode is not
1492 * incorrectly changed after the pspoll failure active window.
1493 */
1494 if (changed & IEEE80211_CONF_CHANGE_PS)
1495 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1496
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001497 if (conf->flags & IEEE80211_CONF_PS &&
1498 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1499 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500
1501 /*
1502 * We enter PSM only if we're already associated.
1503 * If we're not, we'll enter it when joining an SSID,
1504 * through the bss_info_changed() hook.
1505 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001506 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001507 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001508 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001509 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001510 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001512 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001513 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001515 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001517 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001518 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001519 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520 }
1521
1522 if (conf->power_level != wl->power_level) {
1523 ret = wl1271_acx_tx_power(wl, conf->power_level);
1524 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001525 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526
1527 wl->power_level = conf->power_level;
1528 }
1529
1530out_sleep:
1531 wl1271_ps_elp_sleep(wl);
1532
1533out:
1534 mutex_unlock(&wl->mutex);
1535
1536 return ret;
1537}
1538
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001539struct wl1271_filter_params {
1540 bool enabled;
1541 int mc_list_length;
1542 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1543};
1544
Jiri Pirko22bedad2010-04-01 21:22:57 +00001545static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1546 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001547{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001548 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001549 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001550 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001551
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001552 if (unlikely(wl->state == WL1271_STATE_OFF))
1553 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001554
Juuso Oikarinen74441132009-10-13 12:47:53 +03001555 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001556 if (!fp) {
1557 wl1271_error("Out of memory setting filters.");
1558 return 0;
1559 }
1560
1561 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001562 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001563 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1564 fp->enabled = false;
1565 } else {
1566 fp->enabled = true;
1567 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001569 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001570 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001571 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001572 }
1573
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001574 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001575}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001576
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001577#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1578 FIF_ALLMULTI | \
1579 FIF_FCSFAIL | \
1580 FIF_BCN_PRBRESP_PROMISC | \
1581 FIF_CONTROL | \
1582 FIF_OTHER_BSS)
1583
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1585 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001586 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001588 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001589 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001590 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001591
1592 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1593
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001594 mutex_lock(&wl->mutex);
1595
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001596 *total &= WL1271_SUPPORTED_FILTERS;
1597 changed &= WL1271_SUPPORTED_FILTERS;
1598
1599 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001600 goto out;
1601
1602 ret = wl1271_ps_elp_wakeup(wl, false);
1603 if (ret < 0)
1604 goto out;
1605
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001607 if (*total & FIF_ALLMULTI)
1608 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1609 else if (fp)
1610 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1611 fp->mc_list,
1612 fp->mc_list_length);
1613 if (ret < 0)
1614 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001616 /* determine, whether supported filter values have changed */
1617 if (changed == 0)
1618 goto out_sleep;
1619
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001620 /* configure filters */
1621 wl->filters = *total;
1622 wl1271_configure_filters(wl, 0);
1623
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001624 /* apply configured filters */
1625 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1626 if (ret < 0)
1627 goto out_sleep;
1628
1629out_sleep:
1630 wl1271_ps_elp_sleep(wl);
1631
1632out:
1633 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001634 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635}
1636
1637static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1638 struct ieee80211_vif *vif,
1639 struct ieee80211_sta *sta,
1640 struct ieee80211_key_conf *key_conf)
1641{
1642 struct wl1271 *wl = hw->priv;
1643 const u8 *addr;
1644 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001645 u32 tx_seq_32 = 0;
1646 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647 u8 key_type;
1648
1649 static const u8 bcast_addr[ETH_ALEN] =
1650 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1651
1652 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1653
1654 addr = sta ? sta->addr : bcast_addr;
1655
1656 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1657 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1658 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001659 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001660 key_conf->keylen, key_conf->flags);
1661 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1662
1663 if (is_zero_ether_addr(addr)) {
1664 /* We dont support TX only encryption */
1665 ret = -EOPNOTSUPP;
1666 goto out;
1667 }
1668
1669 mutex_lock(&wl->mutex);
1670
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001671 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1672 ret = -EAGAIN;
1673 goto out_unlock;
1674 }
1675
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 ret = wl1271_ps_elp_wakeup(wl, false);
1677 if (ret < 0)
1678 goto out_unlock;
1679
Johannes Berg97359d12010-08-10 09:46:38 +02001680 switch (key_conf->cipher) {
1681 case WLAN_CIPHER_SUITE_WEP40:
1682 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683 key_type = KEY_WEP;
1684
1685 key_conf->hw_key_idx = key_conf->keyidx;
1686 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001687 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 key_type = KEY_TKIP;
1689
1690 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001691 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1692 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001694 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695 key_type = KEY_AES;
1696
1697 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001698 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1699 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001701 case WL1271_CIPHER_SUITE_GEM:
1702 key_type = KEY_GEM;
1703 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1704 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1705 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001706 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001707 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708
1709 ret = -EOPNOTSUPP;
1710 goto out_sleep;
1711 }
1712
1713 switch (cmd) {
1714 case SET_KEY:
1715 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1716 key_conf->keyidx, key_type,
1717 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001718 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001719 if (ret < 0) {
1720 wl1271_error("Could not add or replace key");
1721 goto out_sleep;
1722 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001723
1724 /* the default WEP key needs to be configured at least once */
1725 if (key_type == KEY_WEP) {
1726 ret = wl1271_cmd_set_default_wep_key(wl,
1727 wl->default_key);
1728 if (ret < 0)
1729 goto out_sleep;
1730 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731 break;
1732
1733 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001734 /* The wl1271 does not allow to remove unicast keys - they
1735 will be cleared automatically on next CMD_JOIN. Ignore the
1736 request silently, as we dont want the mac80211 to emit
1737 an error message. */
1738 if (!is_broadcast_ether_addr(addr))
1739 break;
1740
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001741 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1742 key_conf->keyidx, key_type,
1743 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001744 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001745 if (ret < 0) {
1746 wl1271_error("Could not remove key");
1747 goto out_sleep;
1748 }
1749 break;
1750
1751 default:
1752 wl1271_error("Unsupported key cmd 0x%x", cmd);
1753 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001754 break;
1755 }
1756
1757out_sleep:
1758 wl1271_ps_elp_sleep(wl);
1759
1760out_unlock:
1761 mutex_unlock(&wl->mutex);
1762
1763out:
1764 return ret;
1765}
1766
1767static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001768 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769 struct cfg80211_scan_request *req)
1770{
1771 struct wl1271 *wl = hw->priv;
1772 int ret;
1773 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001774 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775
1776 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1777
1778 if (req->n_ssids) {
1779 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001780 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001781 }
1782
1783 mutex_lock(&wl->mutex);
1784
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001785 if (wl->state == WL1271_STATE_OFF) {
1786 /*
1787 * We cannot return -EBUSY here because cfg80211 will expect
1788 * a call to ieee80211_scan_completed if we do - in this case
1789 * there won't be any call.
1790 */
1791 ret = -EAGAIN;
1792 goto out;
1793 }
1794
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 ret = wl1271_ps_elp_wakeup(wl, false);
1796 if (ret < 0)
1797 goto out;
1798
Luciano Coelho5924f892010-08-04 03:46:22 +03001799 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800
1801 wl1271_ps_elp_sleep(wl);
1802
1803out:
1804 mutex_unlock(&wl->mutex);
1805
1806 return ret;
1807}
1808
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001809static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1810{
1811 struct wl1271 *wl = hw->priv;
1812 int ret = 0;
1813
1814 mutex_lock(&wl->mutex);
1815
1816 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1817 ret = -EAGAIN;
1818 goto out;
1819 }
1820
1821 ret = wl1271_ps_elp_wakeup(wl, false);
1822 if (ret < 0)
1823 goto out;
1824
1825 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1826 if (ret < 0)
1827 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1828
1829 wl1271_ps_elp_sleep(wl);
1830
1831out:
1832 mutex_unlock(&wl->mutex);
1833
1834 return ret;
1835}
1836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1838{
1839 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001840 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841
1842 mutex_lock(&wl->mutex);
1843
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001844 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1845 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001846 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001847 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 ret = wl1271_ps_elp_wakeup(wl, false);
1850 if (ret < 0)
1851 goto out;
1852
1853 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1854 if (ret < 0)
1855 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1856
1857 wl1271_ps_elp_sleep(wl);
1858
1859out:
1860 mutex_unlock(&wl->mutex);
1861
1862 return ret;
1863}
1864
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001865static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
1866 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001867{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001868 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001869
1870 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001871 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001872 if (ptr[0] == WLAN_EID_SSID) {
1873 wl->ssid_len = ptr[1];
1874 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1875 return;
1876 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001877 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001878 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001879 wl1271_error("No SSID in IEs!\n");
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001880}
1881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1883 struct ieee80211_vif *vif,
1884 struct ieee80211_bss_conf *bss_conf,
1885 u32 changed)
1886{
1887 enum wl1271_cmd_ps_mode mode;
1888 struct wl1271 *wl = hw->priv;
Shahar Levi18357852010-10-13 16:09:41 +02001889 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001890 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001891 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001892 int ret;
1893
1894 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1895
1896 mutex_lock(&wl->mutex);
1897
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001898 if (unlikely(wl->state == WL1271_STATE_OFF))
1899 goto out;
1900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001901 ret = wl1271_ps_elp_wakeup(wl, false);
1902 if (ret < 0)
1903 goto out;
1904
Eliad Peller9ee82d52010-09-19 18:55:09 +02001905 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001906 (wl->bss_type == BSS_TYPE_IBSS)) {
1907 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1908 bss_conf->beacon_int);
1909
1910 wl->beacon_int = bss_conf->beacon_int;
1911 do_join = true;
1912 }
1913
Eliad Peller9ee82d52010-09-19 18:55:09 +02001914 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001915 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001916 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1917
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001918 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1919
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001920 if (beacon) {
1921 struct ieee80211_hdr *hdr;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001922 int ieoffset = offsetof(struct ieee80211_mgmt,
1923 u.beacon.variable);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001924
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001925 wl1271_ssid_set(wl, beacon, ieoffset);
1926
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001927 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1928 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001929 beacon->len, 0,
1930 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001931
1932 if (ret < 0) {
1933 dev_kfree_skb(beacon);
1934 goto out_sleep;
1935 }
1936
1937 hdr = (struct ieee80211_hdr *) beacon->data;
1938 hdr->frame_control = cpu_to_le16(
1939 IEEE80211_FTYPE_MGMT |
1940 IEEE80211_STYPE_PROBE_RESP);
1941
1942 ret = wl1271_cmd_template_set(wl,
1943 CMD_TEMPL_PROBE_RESPONSE,
1944 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001945 beacon->len, 0,
1946 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001947 dev_kfree_skb(beacon);
1948 if (ret < 0)
1949 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001950
1951 /* Need to update the SSID (for filtering etc) */
1952 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001953 }
1954 }
1955
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001956 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1957 (wl->bss_type == BSS_TYPE_IBSS)) {
1958 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1959 bss_conf->enable_beacon ? "enabled" : "disabled");
1960
1961 if (bss_conf->enable_beacon)
1962 wl->set_bss_type = BSS_TYPE_IBSS;
1963 else
1964 wl->set_bss_type = BSS_TYPE_STA_BSS;
1965 do_join = true;
1966 }
1967
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001968 if (changed & BSS_CHANGED_CQM) {
1969 bool enable = false;
1970 if (bss_conf->cqm_rssi_thold)
1971 enable = true;
1972 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1973 bss_conf->cqm_rssi_thold,
1974 bss_conf->cqm_rssi_hyst);
1975 if (ret < 0)
1976 goto out;
1977 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1978 }
1979
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001980 if ((changed & BSS_CHANGED_BSSID) &&
1981 /*
1982 * Now we know the correct bssid, so we send a new join command
1983 * and enable the BSSID filter
1984 */
1985 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001986 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001987
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001988 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001989 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001990 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001991
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001992 ret = wl1271_build_qos_null_data(wl);
1993 if (ret < 0)
1994 goto out_sleep;
1995
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001996 /* filter out all packets not from this BSSID */
1997 wl1271_configure_filters(wl, 0);
1998
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001999 /* Need to update the BSSID (for filtering etc) */
2000 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002001 }
2002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 if (changed & BSS_CHANGED_ASSOC) {
2004 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002005 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002006 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002008 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002010 wl->ps_poll_failures = 0;
2011
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002012 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002013 * use basic rates from AP, and determine lowest rate
2014 * to use with control frames.
2015 */
2016 rates = bss_conf->basic_rates;
2017 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2018 rates);
2019 wl->basic_rate = wl1271_min_rate_get(wl);
2020 ret = wl1271_acx_rate_policies(wl);
2021 if (ret < 0)
2022 goto out_sleep;
2023
2024 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002025 * with wl1271, we don't need to update the
2026 * beacon_int and dtim_period, because the firmware
2027 * updates it by itself when the first beacon is
2028 * received after a join.
2029 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2031 if (ret < 0)
2032 goto out_sleep;
2033
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002034 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002035 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002036 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002037 dev_kfree_skb(wl->probereq);
2038 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2039 ieoffset = offsetof(struct ieee80211_mgmt,
2040 u.probe_req.variable);
2041 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002042
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002043 /* enable the connection monitoring feature */
2044 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045 if (ret < 0)
2046 goto out_sleep;
2047
2048 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002049 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2050 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002052 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002053 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002054 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 if (ret < 0)
2056 goto out_sleep;
2057 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002058 } else {
2059 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002060 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002061 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002062 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002063
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002064 /* free probe-request template */
2065 dev_kfree_skb(wl->probereq);
2066 wl->probereq = NULL;
2067
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002068 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002069 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002070
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002071 /* revert back to minimum rates for the current band */
2072 wl1271_set_band_rate(wl);
2073 wl->basic_rate = wl1271_min_rate_get(wl);
2074 ret = wl1271_acx_rate_policies(wl);
2075 if (ret < 0)
2076 goto out_sleep;
2077
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002078 /* disable connection monitor features */
2079 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002080
2081 /* Disable the keep-alive feature */
2082 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002083 if (ret < 0)
2084 goto out_sleep;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002085
2086 /* restore the bssid filter and go to dummy bssid */
2087 wl1271_unjoin(wl);
2088 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002089 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002090
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002092
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002093 if (changed & BSS_CHANGED_ERP_SLOT) {
2094 if (bss_conf->use_short_slot)
2095 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2096 else
2097 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2098 if (ret < 0) {
2099 wl1271_warning("Set slot time failed %d", ret);
2100 goto out_sleep;
2101 }
2102 }
2103
2104 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2105 if (bss_conf->use_short_preamble)
2106 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2107 else
2108 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2109 }
2110
2111 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2112 if (bss_conf->use_cts_prot)
2113 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2114 else
2115 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2116 if (ret < 0) {
2117 wl1271_warning("Set ctsprotect failed %d", ret);
2118 goto out_sleep;
2119 }
2120 }
2121
Shahar Levi18357852010-10-13 16:09:41 +02002122 /*
2123 * Takes care of: New association with HT enable,
2124 * HT information change in beacon.
2125 */
2126 if (sta &&
2127 (changed & BSS_CHANGED_HT) &&
2128 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2129 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2130 if (ret < 0) {
2131 wl1271_warning("Set ht cap true failed %d", ret);
2132 goto out_sleep;
2133 }
2134 ret = wl1271_acx_set_ht_information(wl,
2135 bss_conf->ht_operation_mode);
2136 if (ret < 0) {
2137 wl1271_warning("Set ht information failed %d", ret);
2138 goto out_sleep;
2139 }
2140 }
2141 /*
2142 * Takes care of: New association without HT,
2143 * Disassociation.
2144 */
2145 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2146 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2147 if (ret < 0) {
2148 wl1271_warning("Set ht cap false failed %d", ret);
2149 goto out_sleep;
2150 }
2151 }
2152
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002153 if (changed & BSS_CHANGED_ARP_FILTER) {
2154 __be32 addr = bss_conf->arp_addr_list[0];
2155 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2156
Eliad Pellerc5312772010-12-09 11:31:27 +02002157 if (bss_conf->arp_addr_cnt == 1 &&
2158 bss_conf->arp_filter_enabled) {
2159 /*
2160 * The template should have been configured only upon
2161 * association. however, it seems that the correct ip
2162 * isn't being set (when sending), so we have to
2163 * reconfigure the template upon every ip change.
2164 */
2165 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2166 if (ret < 0) {
2167 wl1271_warning("build arp rsp failed: %d", ret);
2168 goto out_sleep;
2169 }
2170
2171 ret = wl1271_acx_arp_ip_filter(wl,
2172 (ACX_ARP_FILTER_ARP_FILTERING |
2173 ACX_ARP_FILTER_AUTO_ARP),
2174 addr);
2175 } else
2176 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002177
2178 if (ret < 0)
2179 goto out_sleep;
2180 }
2181
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002182 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002183 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002184 if (ret < 0) {
2185 wl1271_warning("cmd join failed %d", ret);
2186 goto out_sleep;
2187 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002188 }
2189
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190out_sleep:
2191 wl1271_ps_elp_sleep(wl);
2192
2193out:
2194 mutex_unlock(&wl->mutex);
2195}
2196
Kalle Valoc6999d82010-02-18 13:25:41 +02002197static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2198 const struct ieee80211_tx_queue_params *params)
2199{
2200 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002201 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002202 int ret;
2203
2204 mutex_lock(&wl->mutex);
2205
2206 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2207
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002208 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2209 ret = -EAGAIN;
2210 goto out;
2211 }
2212
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002213 ret = wl1271_ps_elp_wakeup(wl, false);
2214 if (ret < 0)
2215 goto out;
2216
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002217 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002218 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2219 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002220 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002221 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002222 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002223
Kalle Valo4695dc92010-03-18 12:26:38 +02002224 if (params->uapsd)
2225 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2226 else
2227 ps_scheme = CONF_PS_SCHEME_LEGACY;
2228
Kalle Valoc6999d82010-02-18 13:25:41 +02002229 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2230 CONF_CHANNEL_TYPE_EDCF,
2231 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002232 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002233 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002234 goto out_sleep;
2235
2236out_sleep:
2237 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002238
2239out:
2240 mutex_unlock(&wl->mutex);
2241
2242 return ret;
2243}
2244
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002245static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2246{
2247
2248 struct wl1271 *wl = hw->priv;
2249 u64 mactime = ULLONG_MAX;
2250 int ret;
2251
2252 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2253
2254 mutex_lock(&wl->mutex);
2255
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002256 if (unlikely(wl->state == WL1271_STATE_OFF))
2257 goto out;
2258
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002259 ret = wl1271_ps_elp_wakeup(wl, false);
2260 if (ret < 0)
2261 goto out;
2262
2263 ret = wl1271_acx_tsf_info(wl, &mactime);
2264 if (ret < 0)
2265 goto out_sleep;
2266
2267out_sleep:
2268 wl1271_ps_elp_sleep(wl);
2269
2270out:
2271 mutex_unlock(&wl->mutex);
2272 return mactime;
2273}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002274
John W. Linvilleece550d2010-07-28 16:41:06 -04002275static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2276 struct survey_info *survey)
2277{
2278 struct wl1271 *wl = hw->priv;
2279 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002280
John W. Linvilleece550d2010-07-28 16:41:06 -04002281 if (idx != 0)
2282 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002283
John W. Linvilleece550d2010-07-28 16:41:06 -04002284 survey->channel = conf->channel;
2285 survey->filled = SURVEY_INFO_NOISE_DBM;
2286 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002287
John W. Linvilleece550d2010-07-28 16:41:06 -04002288 return 0;
2289}
2290
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291/* can't be const, mac80211 writes to this */
2292static struct ieee80211_rate wl1271_rates[] = {
2293 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002294 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2295 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002297 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2298 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2300 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002301 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2302 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2304 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002305 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2306 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002307 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2308 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002309 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2310 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002312 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2313 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002315 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2316 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002318 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2319 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002321 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2322 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002324 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2325 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002326 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002327 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2328 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002330 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2331 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332};
2333
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002334/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002336 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002337 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002338 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2339 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2340 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002341 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002342 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2343 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2344 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002345 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002346 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2347 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2348 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349};
2350
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002351/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002352static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002353 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002354 7, /* CONF_HW_RXTX_RATE_MCS7 */
2355 6, /* CONF_HW_RXTX_RATE_MCS6 */
2356 5, /* CONF_HW_RXTX_RATE_MCS5 */
2357 4, /* CONF_HW_RXTX_RATE_MCS4 */
2358 3, /* CONF_HW_RXTX_RATE_MCS3 */
2359 2, /* CONF_HW_RXTX_RATE_MCS2 */
2360 1, /* CONF_HW_RXTX_RATE_MCS1 */
2361 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002362
2363 11, /* CONF_HW_RXTX_RATE_54 */
2364 10, /* CONF_HW_RXTX_RATE_48 */
2365 9, /* CONF_HW_RXTX_RATE_36 */
2366 8, /* CONF_HW_RXTX_RATE_24 */
2367
2368 /* TI-specific rate */
2369 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2370
2371 7, /* CONF_HW_RXTX_RATE_18 */
2372 6, /* CONF_HW_RXTX_RATE_12 */
2373 3, /* CONF_HW_RXTX_RATE_11 */
2374 5, /* CONF_HW_RXTX_RATE_9 */
2375 4, /* CONF_HW_RXTX_RATE_6 */
2376 2, /* CONF_HW_RXTX_RATE_5_5 */
2377 1, /* CONF_HW_RXTX_RATE_2 */
2378 0 /* CONF_HW_RXTX_RATE_1 */
2379};
2380
Shahar Levie8b03a22010-10-13 16:09:39 +02002381/* 11n STA capabilities */
2382#define HW_RX_HIGHEST_RATE 72
2383
Shahar Levi00d20102010-11-08 11:20:10 +00002384#ifdef CONFIG_WL12XX_HT
2385#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002386 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2387 .ht_supported = true, \
2388 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2389 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2390 .mcs = { \
2391 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2392 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2393 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2394 }, \
2395}
Shahar Levi18357852010-10-13 16:09:41 +02002396#else
Shahar Levi00d20102010-11-08 11:20:10 +00002397#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002398 .ht_supported = false, \
2399}
2400#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402/* can't be const, mac80211 writes to this */
2403static struct ieee80211_supported_band wl1271_band_2ghz = {
2404 .channels = wl1271_channels,
2405 .n_channels = ARRAY_SIZE(wl1271_channels),
2406 .bitrates = wl1271_rates,
2407 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002408 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409};
2410
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002411/* 5 GHz data rates for WL1273 */
2412static struct ieee80211_rate wl1271_rates_5ghz[] = {
2413 { .bitrate = 60,
2414 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2415 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2416 { .bitrate = 90,
2417 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2418 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2419 { .bitrate = 120,
2420 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2421 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2422 { .bitrate = 180,
2423 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2424 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2425 { .bitrate = 240,
2426 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2427 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2428 { .bitrate = 360,
2429 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2430 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2431 { .bitrate = 480,
2432 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2433 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2434 { .bitrate = 540,
2435 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2436 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2437};
2438
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002439/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002440static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002441 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002442 { .hw_value = 8, .center_freq = 5040},
2443 { .hw_value = 9, .center_freq = 5045},
2444 { .hw_value = 11, .center_freq = 5055},
2445 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002446 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002447 { .hw_value = 34, .center_freq = 5170},
2448 { .hw_value = 36, .center_freq = 5180},
2449 { .hw_value = 38, .center_freq = 5190},
2450 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002451 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002452 { .hw_value = 44, .center_freq = 5220},
2453 { .hw_value = 46, .center_freq = 5230},
2454 { .hw_value = 48, .center_freq = 5240},
2455 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002456 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002457 { .hw_value = 60, .center_freq = 5300},
2458 { .hw_value = 64, .center_freq = 5320},
2459 { .hw_value = 100, .center_freq = 5500},
2460 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002461 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002462 { .hw_value = 112, .center_freq = 5560},
2463 { .hw_value = 116, .center_freq = 5580},
2464 { .hw_value = 120, .center_freq = 5600},
2465 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002466 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002467 { .hw_value = 132, .center_freq = 5660},
2468 { .hw_value = 136, .center_freq = 5680},
2469 { .hw_value = 140, .center_freq = 5700},
2470 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002471 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002472 { .hw_value = 157, .center_freq = 5785},
2473 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002474 { .hw_value = 165, .center_freq = 5825},
2475};
2476
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002477/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002478static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002479 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002480 7, /* CONF_HW_RXTX_RATE_MCS7 */
2481 6, /* CONF_HW_RXTX_RATE_MCS6 */
2482 5, /* CONF_HW_RXTX_RATE_MCS5 */
2483 4, /* CONF_HW_RXTX_RATE_MCS4 */
2484 3, /* CONF_HW_RXTX_RATE_MCS3 */
2485 2, /* CONF_HW_RXTX_RATE_MCS2 */
2486 1, /* CONF_HW_RXTX_RATE_MCS1 */
2487 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002488
2489 7, /* CONF_HW_RXTX_RATE_54 */
2490 6, /* CONF_HW_RXTX_RATE_48 */
2491 5, /* CONF_HW_RXTX_RATE_36 */
2492 4, /* CONF_HW_RXTX_RATE_24 */
2493
2494 /* TI-specific rate */
2495 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2496
2497 3, /* CONF_HW_RXTX_RATE_18 */
2498 2, /* CONF_HW_RXTX_RATE_12 */
2499 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2500 1, /* CONF_HW_RXTX_RATE_9 */
2501 0, /* CONF_HW_RXTX_RATE_6 */
2502 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2503 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2504 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2505};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002506
2507static struct ieee80211_supported_band wl1271_band_5ghz = {
2508 .channels = wl1271_channels_5ghz,
2509 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2510 .bitrates = wl1271_rates_5ghz,
2511 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002512 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002513};
2514
Tobias Klausera0ea9492010-05-20 10:38:11 +02002515static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002516 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2517 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2518};
2519
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520static const struct ieee80211_ops wl1271_ops = {
2521 .start = wl1271_op_start,
2522 .stop = wl1271_op_stop,
2523 .add_interface = wl1271_op_add_interface,
2524 .remove_interface = wl1271_op_remove_interface,
2525 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002526 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002527 .configure_filter = wl1271_op_configure_filter,
2528 .tx = wl1271_op_tx,
2529 .set_key = wl1271_op_set_key,
2530 .hw_scan = wl1271_op_hw_scan,
2531 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002532 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002534 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002535 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002536 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002537 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538};
2539
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002540
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002541u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002542{
2543 u8 idx;
2544
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002545 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002546
2547 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2548 wl1271_error("Illegal RX rate from HW: %d", rate);
2549 return 0;
2550 }
2551
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002552 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002553 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2554 wl1271_error("Unsupported RX rate from HW: %d", rate);
2555 return 0;
2556 }
2557
2558 return idx;
2559}
2560
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002561static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2562 struct device_attribute *attr,
2563 char *buf)
2564{
2565 struct wl1271 *wl = dev_get_drvdata(dev);
2566 ssize_t len;
2567
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002568 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002569
2570 mutex_lock(&wl->mutex);
2571 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2572 wl->sg_enabled);
2573 mutex_unlock(&wl->mutex);
2574
2575 return len;
2576
2577}
2578
2579static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2580 struct device_attribute *attr,
2581 const char *buf, size_t count)
2582{
2583 struct wl1271 *wl = dev_get_drvdata(dev);
2584 unsigned long res;
2585 int ret;
2586
2587 ret = strict_strtoul(buf, 10, &res);
2588
2589 if (ret < 0) {
2590 wl1271_warning("incorrect value written to bt_coex_mode");
2591 return count;
2592 }
2593
2594 mutex_lock(&wl->mutex);
2595
2596 res = !!res;
2597
2598 if (res == wl->sg_enabled)
2599 goto out;
2600
2601 wl->sg_enabled = res;
2602
2603 if (wl->state == WL1271_STATE_OFF)
2604 goto out;
2605
2606 ret = wl1271_ps_elp_wakeup(wl, false);
2607 if (ret < 0)
2608 goto out;
2609
2610 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2611 wl1271_ps_elp_sleep(wl);
2612
2613 out:
2614 mutex_unlock(&wl->mutex);
2615 return count;
2616}
2617
2618static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2619 wl1271_sysfs_show_bt_coex_state,
2620 wl1271_sysfs_store_bt_coex_state);
2621
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002622static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2623 struct device_attribute *attr,
2624 char *buf)
2625{
2626 struct wl1271 *wl = dev_get_drvdata(dev);
2627 ssize_t len;
2628
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002629 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002630
2631 mutex_lock(&wl->mutex);
2632 if (wl->hw_pg_ver >= 0)
2633 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2634 else
2635 len = snprintf(buf, len, "n/a\n");
2636 mutex_unlock(&wl->mutex);
2637
2638 return len;
2639}
2640
2641static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2642 wl1271_sysfs_show_hw_pg_ver, NULL);
2643
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002644int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002645{
2646 int ret;
2647
2648 if (wl->mac80211_registered)
2649 return 0;
2650
2651 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2652
2653 ret = ieee80211_register_hw(wl->hw);
2654 if (ret < 0) {
2655 wl1271_error("unable to register mac80211 hw: %d", ret);
2656 return ret;
2657 }
2658
2659 wl->mac80211_registered = true;
2660
Eliad Pellerd60080a2010-11-24 12:53:16 +02002661 wl1271_debugfs_init(wl);
2662
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002663 register_netdevice_notifier(&wl1271_dev_notifier);
2664
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665 wl1271_notice("loaded");
2666
2667 return 0;
2668}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002669EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002670
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002671void wl1271_unregister_hw(struct wl1271 *wl)
2672{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002673 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002674 ieee80211_unregister_hw(wl->hw);
2675 wl->mac80211_registered = false;
2676
2677}
2678EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2679
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002680int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002682 static const u32 cipher_suites[] = {
2683 WLAN_CIPHER_SUITE_WEP40,
2684 WLAN_CIPHER_SUITE_WEP104,
2685 WLAN_CIPHER_SUITE_TKIP,
2686 WLAN_CIPHER_SUITE_CCMP,
2687 WL1271_CIPHER_SUITE_GEM,
2688 };
2689
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002690 /* The tx descriptor buffer and the TKIP space. */
2691 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2692 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693
2694 /* unit us */
2695 /* FIXME: find a proper value */
2696 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002697 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002698
2699 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002700 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002701 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002702 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002703 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002704 IEEE80211_HW_CONNECTION_MONITOR |
2705 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002707 wl->hw->wiphy->cipher_suites = cipher_suites;
2708 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2709
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002710 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2711 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02002713 /*
2714 * Maximum length of elements in scanning probe request templates
2715 * should be the maximum length possible for a template, without
2716 * the IEEE80211 header of the template
2717 */
2718 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
2719 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002721 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002722
Kalle Valo12bd8942010-03-18 12:26:33 +02002723 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002724 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002725
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002726 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2727
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002728 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002729
2730 return 0;
2731}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002732EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002735
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002736struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002739 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002741 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002742 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743
2744 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2745 if (!hw) {
2746 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002747 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002748 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749 }
2750
Julia Lawall929ebd32010-05-15 23:16:39 +02002751 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002752 if (!plat_dev) {
2753 wl1271_error("could not allocate platform_device");
2754 ret = -ENOMEM;
2755 goto err_plat_alloc;
2756 }
2757
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 wl = hw->priv;
2759 memset(wl, 0, sizeof(*wl));
2760
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002761 INIT_LIST_HEAD(&wl->list);
2762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002763 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002764 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002765
Juuso Oikarinen6742f552010-12-13 09:52:37 +02002766 for (i = 0; i < NUM_TX_QUEUES; i++)
2767 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002768
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002769 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002770 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002771 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2772 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2773 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2774 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002775 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002776 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002777 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002778 wl->rx_counter = 0;
2779 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2780 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002781 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002783 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002784 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002785 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2786 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002787 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002788 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002789 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002790 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002791 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002792
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002793 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002794 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002795 wl->tx_frames[i] = NULL;
2796
2797 spin_lock_init(&wl->wl_lock);
2798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 wl->state = WL1271_STATE_OFF;
2800 mutex_init(&wl->mutex);
2801
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002802 /* Apply default driver configuration. */
2803 wl1271_conf_init(wl);
2804
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002805 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2806 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2807 if (!wl->aggr_buf) {
2808 ret = -ENOMEM;
2809 goto err_hw;
2810 }
2811
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002812 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002813 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002814 if (ret) {
2815 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002816 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002817 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002818 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002819
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002820 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002821 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002822 if (ret < 0) {
2823 wl1271_error("failed to create sysfs file bt_coex_state");
2824 goto err_platform;
2825 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002826
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002827 /* Create sysfs file to get HW PG version */
2828 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2829 if (ret < 0) {
2830 wl1271_error("failed to create sysfs file hw_pg_ver");
2831 goto err_bt_coex_state;
2832 }
2833
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002834 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002835
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002836err_bt_coex_state:
2837 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2838
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002839err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002840 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002841
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002842err_aggr:
2843 free_pages((unsigned long)wl->aggr_buf, order);
2844
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002845err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002846 wl1271_debugfs_exit(wl);
2847 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002848
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002849err_plat_alloc:
2850 ieee80211_free_hw(hw);
2851
2852err_hw_alloc:
2853
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002854 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002855}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002856EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002857
2858int wl1271_free_hw(struct wl1271 *wl)
2859{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002860 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002861 free_pages((unsigned long)wl->aggr_buf,
2862 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002863 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002864
2865 wl1271_debugfs_exit(wl);
2866
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002867 vfree(wl->fw);
2868 wl->fw = NULL;
2869 kfree(wl->nvs);
2870 wl->nvs = NULL;
2871
2872 kfree(wl->fw_status);
2873 kfree(wl->tx_res_if);
2874
2875 ieee80211_free_hw(wl->hw);
2876
2877 return 0;
2878}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002879EXPORT_SYMBOL_GPL(wl1271_free_hw);
2880
Eliad Peller17c17552010-12-12 12:15:35 +02002881u32 wl12xx_debug_level;
2882EXPORT_SYMBOL_GPL(wl12xx_debug_level);
2883module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
2884MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
2885
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002886MODULE_LICENSE("GPL");
2887MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2888MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");