blob: 8e5d435f63f7062fdda0af2f2aa257b8b3f7de6d [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 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
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
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200437 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200438 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 Coelhod6e19d132009-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{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001230 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001231
1232 /* combine requested filters with current filter config */
1233 filters = wl->filters | filters;
1234
1235 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1236
1237 if (filters & FIF_PROMISC_IN_BSS) {
1238 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1239 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1240 wl->rx_config |= CFG_BSSID_FILTER_EN;
1241 }
1242 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1243 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1244 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1245 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1246 }
1247 if (filters & FIF_OTHER_BSS) {
1248 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1249 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1250 }
1251 if (filters & FIF_CONTROL) {
1252 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1253 wl->rx_filter |= CFG_RX_CTL_EN;
1254 }
1255 if (filters & FIF_FCSFAIL) {
1256 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1257 wl->rx_filter |= CFG_RX_FCS_ERROR;
1258 }
1259}
1260
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001261static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001262{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001263 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001264 /* we need to use a dummy BSSID for now */
1265 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1266 0xad, 0xbe, 0xef };
1267
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001268 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1269
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001270 /* pass through frames from all BSS */
1271 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1272
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001273 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001274 if (ret < 0)
1275 goto out;
1276
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001277 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001278
1279out:
1280 return ret;
1281}
1282
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001283static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001284{
1285 int ret;
1286
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001287 /*
1288 * One of the side effects of the JOIN command is that is clears
1289 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1290 * to a WPA/WPA2 access point will therefore kill the data-path.
1291 * Currently there is no supported scenario for JOIN during
1292 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1293 * must be handled somehow.
1294 *
1295 */
1296 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1297 wl1271_info("JOIN while associated.");
1298
1299 if (set_assoc)
1300 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1301
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001302 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1303 if (ret < 0)
1304 goto out;
1305
1306 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1307
1308 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1309 goto out;
1310
1311 /*
1312 * The join command disable the keep-alive mode, shut down its process,
1313 * and also clear the template config, so we need to reset it all after
1314 * the join. The acx_aid starts the keep-alive process, and the order
1315 * of the commands below is relevant.
1316 */
1317 ret = wl1271_acx_keep_alive_mode(wl, true);
1318 if (ret < 0)
1319 goto out;
1320
1321 ret = wl1271_acx_aid(wl, wl->aid);
1322 if (ret < 0)
1323 goto out;
1324
1325 ret = wl1271_cmd_build_klv_null_data(wl);
1326 if (ret < 0)
1327 goto out;
1328
1329 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1330 ACX_KEEP_ALIVE_TPL_VALID);
1331 if (ret < 0)
1332 goto out;
1333
1334out:
1335 return ret;
1336}
1337
1338static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001339{
1340 int ret;
1341
1342 /* to stop listening to a channel, we disconnect */
1343 ret = wl1271_cmd_disconnect(wl);
1344 if (ret < 0)
1345 goto out;
1346
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001347 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001348 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001349
1350 /* stop filterting packets based on bssid */
1351 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001352
1353out:
1354 return ret;
1355}
1356
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001357static void wl1271_set_band_rate(struct wl1271 *wl)
1358{
1359 if (wl->band == IEEE80211_BAND_2GHZ)
1360 wl->basic_rate_set = wl->conf.tx.basic_rate;
1361 else
1362 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1363}
1364
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001365static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001366{
1367 int ret;
1368
1369 if (idle) {
1370 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1371 ret = wl1271_unjoin(wl);
1372 if (ret < 0)
1373 goto out;
1374 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001375 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001376 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001377 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001378 if (ret < 0)
1379 goto out;
1380 ret = wl1271_acx_keep_alive_config(
1381 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1382 ACX_KEEP_ALIVE_TPL_INVALID);
1383 if (ret < 0)
1384 goto out;
1385 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1386 } else {
1387 /* increment the session counter */
1388 wl->session_counter++;
1389 if (wl->session_counter >= SESSION_COUNTER_MAX)
1390 wl->session_counter = 0;
1391 ret = wl1271_dummy_join(wl);
1392 if (ret < 0)
1393 goto out;
1394 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1395 }
1396
1397out:
1398 return ret;
1399}
1400
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1402{
1403 struct wl1271 *wl = hw->priv;
1404 struct ieee80211_conf *conf = &hw->conf;
1405 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001406 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
1408 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1409
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001410 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1411 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 channel,
1413 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001414 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001415 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1416 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001418 /*
1419 * mac80211 will go to idle nearly immediately after transmitting some
1420 * frames, such as the deauth. To make sure those frames reach the air,
1421 * wait here until the TX queue is fully flushed.
1422 */
1423 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1424 (conf->flags & IEEE80211_CONF_IDLE))
1425 wl1271_tx_flush(wl);
1426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427 mutex_lock(&wl->mutex);
1428
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001429 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1430 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001431 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001432 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001433
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001434 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1435
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 ret = wl1271_ps_elp_wakeup(wl, false);
1437 if (ret < 0)
1438 goto out;
1439
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001440 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001441 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1442 ((wl->band != conf->channel->band) ||
1443 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001444 wl->band = conf->channel->band;
1445 wl->channel = channel;
1446
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001447 if (!is_ap) {
1448 /*
1449 * FIXME: the mac80211 should really provide a fixed
1450 * rate to use here. for now, just use the smallest
1451 * possible rate for the band as a fixed rate for
1452 * association frames and other control messages.
1453 */
1454 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1455 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001456
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001457 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1458 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001459 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001460 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001461 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001462
1463 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1464 ret = wl1271_join(wl, false);
1465 if (ret < 0)
1466 wl1271_warning("cmd join on channel "
1467 "failed %d", ret);
1468 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001469 }
1470 }
1471
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001472 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1473 ret = wl1271_sta_handle_idle(wl,
1474 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001475 if (ret < 0)
1476 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001477 }
1478
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001479 /*
1480 * if mac80211 changes the PSM mode, make sure the mode is not
1481 * incorrectly changed after the pspoll failure active window.
1482 */
1483 if (changed & IEEE80211_CONF_CHANGE_PS)
1484 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1485
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001486 if (conf->flags & IEEE80211_CONF_PS &&
1487 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1488 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489
1490 /*
1491 * We enter PSM only if we're already associated.
1492 * If we're not, we'll enter it when joining an SSID,
1493 * through the bss_info_changed() hook.
1494 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001496 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001497 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001498 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001499 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001501 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001502 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001504 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001506 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001507 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001508 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 }
1510
1511 if (conf->power_level != wl->power_level) {
1512 ret = wl1271_acx_tx_power(wl, conf->power_level);
1513 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001514 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
1516 wl->power_level = conf->power_level;
1517 }
1518
1519out_sleep:
1520 wl1271_ps_elp_sleep(wl);
1521
1522out:
1523 mutex_unlock(&wl->mutex);
1524
1525 return ret;
1526}
1527
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001528struct wl1271_filter_params {
1529 bool enabled;
1530 int mc_list_length;
1531 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1532};
1533
Jiri Pirko22bedad32010-04-01 21:22:57 +00001534static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1535 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001536{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001537 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001538 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001539 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001540
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001541 if (unlikely(wl->state == WL1271_STATE_OFF))
1542 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001543
Juuso Oikarinen74441132009-10-13 12:47:53 +03001544 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001545 if (!fp) {
1546 wl1271_error("Out of memory setting filters.");
1547 return 0;
1548 }
1549
1550 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001551 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001552 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1553 fp->enabled = false;
1554 } else {
1555 fp->enabled = true;
1556 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001557 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001558 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001559 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001560 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001561 }
1562
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001563 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001564}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001566#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1567 FIF_ALLMULTI | \
1568 FIF_FCSFAIL | \
1569 FIF_BCN_PRBRESP_PROMISC | \
1570 FIF_CONTROL | \
1571 FIF_OTHER_BSS)
1572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1574 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001575 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001576{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001577 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001579 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580
Arik Nemtsov7d057862010-10-16 19:25:35 +02001581 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1582 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001584 mutex_lock(&wl->mutex);
1585
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001586 *total &= WL1271_SUPPORTED_FILTERS;
1587 changed &= WL1271_SUPPORTED_FILTERS;
1588
1589 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001590 goto out;
1591
1592 ret = wl1271_ps_elp_wakeup(wl, false);
1593 if (ret < 0)
1594 goto out;
1595
Arik Nemtsov7d057862010-10-16 19:25:35 +02001596 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1597 if (*total & FIF_ALLMULTI)
1598 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1599 else if (fp)
1600 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1601 fp->mc_list,
1602 fp->mc_list_length);
1603 if (ret < 0)
1604 goto out_sleep;
1605 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001607 /* determine, whether supported filter values have changed */
1608 if (changed == 0)
1609 goto out_sleep;
1610
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001611 /* configure filters */
1612 wl->filters = *total;
1613 wl1271_configure_filters(wl, 0);
1614
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001615 /* apply configured filters */
1616 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1617 if (ret < 0)
1618 goto out_sleep;
1619
1620out_sleep:
1621 wl1271_ps_elp_sleep(wl);
1622
1623out:
1624 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001625 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001626}
1627
1628static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1629 struct ieee80211_vif *vif,
1630 struct ieee80211_sta *sta,
1631 struct ieee80211_key_conf *key_conf)
1632{
1633 struct wl1271 *wl = hw->priv;
1634 const u8 *addr;
1635 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001636 u32 tx_seq_32 = 0;
1637 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638 u8 key_type;
1639
1640 static const u8 bcast_addr[ETH_ALEN] =
1641 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1642
1643 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1644
1645 addr = sta ? sta->addr : bcast_addr;
1646
1647 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1648 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1649 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001650 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001651 key_conf->keylen, key_conf->flags);
1652 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1653
1654 if (is_zero_ether_addr(addr)) {
1655 /* We dont support TX only encryption */
1656 ret = -EOPNOTSUPP;
1657 goto out;
1658 }
1659
1660 mutex_lock(&wl->mutex);
1661
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001662 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1663 ret = -EAGAIN;
1664 goto out_unlock;
1665 }
1666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667 ret = wl1271_ps_elp_wakeup(wl, false);
1668 if (ret < 0)
1669 goto out_unlock;
1670
Johannes Berg97359d12010-08-10 09:46:38 +02001671 switch (key_conf->cipher) {
1672 case WLAN_CIPHER_SUITE_WEP40:
1673 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001674 key_type = KEY_WEP;
1675
1676 key_conf->hw_key_idx = key_conf->keyidx;
1677 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001678 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679 key_type = KEY_TKIP;
1680
1681 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001682 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1683 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001685 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 key_type = KEY_AES;
1687
1688 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001689 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1690 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001691 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001692 case WL1271_CIPHER_SUITE_GEM:
1693 key_type = KEY_GEM;
1694 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1695 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1696 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001698 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699
1700 ret = -EOPNOTSUPP;
1701 goto out_sleep;
1702 }
1703
1704 switch (cmd) {
1705 case SET_KEY:
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001706 ret = wl1271_cmd_set_sta_key(wl, KEY_ADD_OR_REPLACE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 key_conf->keyidx, key_type,
1708 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001709 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001710 if (ret < 0) {
1711 wl1271_error("Could not add or replace key");
1712 goto out_sleep;
1713 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001714
1715 /* the default WEP key needs to be configured at least once */
1716 if (key_type == KEY_WEP) {
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001717 ret = wl1271_cmd_set_sta_default_wep_key(wl,
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001718 wl->default_key);
1719 if (ret < 0)
1720 goto out_sleep;
1721 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722 break;
1723
1724 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001725 /* The wl1271 does not allow to remove unicast keys - they
1726 will be cleared automatically on next CMD_JOIN. Ignore the
1727 request silently, as we dont want the mac80211 to emit
1728 an error message. */
1729 if (!is_broadcast_ether_addr(addr))
1730 break;
1731
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001732 ret = wl1271_cmd_set_sta_key(wl, KEY_REMOVE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001733 key_conf->keyidx, key_type,
1734 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001735 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736 if (ret < 0) {
1737 wl1271_error("Could not remove key");
1738 goto out_sleep;
1739 }
1740 break;
1741
1742 default:
1743 wl1271_error("Unsupported key cmd 0x%x", cmd);
1744 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001745 break;
1746 }
1747
1748out_sleep:
1749 wl1271_ps_elp_sleep(wl);
1750
1751out_unlock:
1752 mutex_unlock(&wl->mutex);
1753
1754out:
1755 return ret;
1756}
1757
1758static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001759 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001760 struct cfg80211_scan_request *req)
1761{
1762 struct wl1271 *wl = hw->priv;
1763 int ret;
1764 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001765 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766
1767 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1768
1769 if (req->n_ssids) {
1770 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001771 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 }
1773
1774 mutex_lock(&wl->mutex);
1775
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001776 if (wl->state == WL1271_STATE_OFF) {
1777 /*
1778 * We cannot return -EBUSY here because cfg80211 will expect
1779 * a call to ieee80211_scan_completed if we do - in this case
1780 * there won't be any call.
1781 */
1782 ret = -EAGAIN;
1783 goto out;
1784 }
1785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786 ret = wl1271_ps_elp_wakeup(wl, false);
1787 if (ret < 0)
1788 goto out;
1789
Luciano Coelho5924f892010-08-04 03:46:22 +03001790 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791
1792 wl1271_ps_elp_sleep(wl);
1793
1794out:
1795 mutex_unlock(&wl->mutex);
1796
1797 return ret;
1798}
1799
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001800static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1801{
1802 struct wl1271 *wl = hw->priv;
1803 int ret = 0;
1804
1805 mutex_lock(&wl->mutex);
1806
1807 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1808 ret = -EAGAIN;
1809 goto out;
1810 }
1811
1812 ret = wl1271_ps_elp_wakeup(wl, false);
1813 if (ret < 0)
1814 goto out;
1815
1816 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1817 if (ret < 0)
1818 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1819
1820 wl1271_ps_elp_sleep(wl);
1821
1822out:
1823 mutex_unlock(&wl->mutex);
1824
1825 return ret;
1826}
1827
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1829{
1830 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001831 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832
1833 mutex_lock(&wl->mutex);
1834
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001835 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1836 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001837 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001838 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001839
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 ret = wl1271_ps_elp_wakeup(wl, false);
1841 if (ret < 0)
1842 goto out;
1843
1844 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1845 if (ret < 0)
1846 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1847
1848 wl1271_ps_elp_sleep(wl);
1849
1850out:
1851 mutex_unlock(&wl->mutex);
1852
1853 return ret;
1854}
1855
Arik Nemtsove78a2872010-10-16 19:07:21 +02001856static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001857 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001858{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001859 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001860
1861 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001862 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001863 if (ptr[0] == WLAN_EID_SSID) {
1864 wl->ssid_len = ptr[1];
1865 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02001866 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001867 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001868 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001869 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02001870
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001871 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02001872 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001873}
1874
Arik Nemtsove78a2872010-10-16 19:07:21 +02001875static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
1876 struct ieee80211_bss_conf *bss_conf,
1877 u32 changed)
1878{
1879 int ret = 0;
1880
1881 if (changed & BSS_CHANGED_ERP_SLOT) {
1882 if (bss_conf->use_short_slot)
1883 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1884 else
1885 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1886 if (ret < 0) {
1887 wl1271_warning("Set slot time failed %d", ret);
1888 goto out;
1889 }
1890 }
1891
1892 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1893 if (bss_conf->use_short_preamble)
1894 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1895 else
1896 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1897 }
1898
1899 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1900 if (bss_conf->use_cts_prot)
1901 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1902 else
1903 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1904 if (ret < 0) {
1905 wl1271_warning("Set ctsprotect failed %d", ret);
1906 goto out;
1907 }
1908 }
1909
1910out:
1911 return ret;
1912}
1913
1914static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
1915 struct ieee80211_vif *vif,
1916 struct ieee80211_bss_conf *bss_conf,
1917 u32 changed)
1918{
1919 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1920 int ret = 0;
1921
1922 if ((changed & BSS_CHANGED_BEACON_INT)) {
1923 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
1924 bss_conf->beacon_int);
1925
1926 wl->beacon_int = bss_conf->beacon_int;
1927 }
1928
1929 if ((changed & BSS_CHANGED_BEACON)) {
1930 struct ieee80211_hdr *hdr;
1931 int ieoffset = offsetof(struct ieee80211_mgmt,
1932 u.beacon.variable);
1933 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
1934 u16 tmpl_id;
1935
1936 if (!beacon)
1937 goto out;
1938
1939 wl1271_debug(DEBUG_MASTER, "beacon updated");
1940
1941 ret = wl1271_ssid_set(wl, beacon, ieoffset);
1942 if (ret < 0) {
1943 dev_kfree_skb(beacon);
1944 goto out;
1945 }
1946 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
1947 CMD_TEMPL_BEACON;
1948 ret = wl1271_cmd_template_set(wl, tmpl_id,
1949 beacon->data,
1950 beacon->len, 0,
1951 wl1271_tx_min_rate_get(wl));
1952 if (ret < 0) {
1953 dev_kfree_skb(beacon);
1954 goto out;
1955 }
1956
1957 hdr = (struct ieee80211_hdr *) beacon->data;
1958 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1959 IEEE80211_STYPE_PROBE_RESP);
1960
1961 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
1962 CMD_TEMPL_PROBE_RESPONSE;
1963 ret = wl1271_cmd_template_set(wl,
1964 tmpl_id,
1965 beacon->data,
1966 beacon->len, 0,
1967 wl1271_tx_min_rate_get(wl));
1968 dev_kfree_skb(beacon);
1969 if (ret < 0)
1970 goto out;
1971 }
1972
1973out:
1974 return ret;
1975}
1976
1977/* AP mode changes */
1978static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979 struct ieee80211_vif *vif,
1980 struct ieee80211_bss_conf *bss_conf,
1981 u32 changed)
1982{
Arik Nemtsove78a2872010-10-16 19:07:21 +02001983 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984
Arik Nemtsove78a2872010-10-16 19:07:21 +02001985 if ((changed & BSS_CHANGED_BASIC_RATES)) {
1986 u32 rates = bss_conf->basic_rates;
1987 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988
Arik Nemtsove78a2872010-10-16 19:07:21 +02001989 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
1990 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1991 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
1992 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993
Arik Nemtsove78a2872010-10-16 19:07:21 +02001994 /* update the AP management rate policy with the new rates */
1995 mgmt_rc.enabled_rates = wl->basic_rate_set;
1996 mgmt_rc.long_retry_limit = 10;
1997 mgmt_rc.short_retry_limit = 10;
1998 mgmt_rc.aflags = 0;
1999 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2000 ACX_TX_AP_MODE_MGMT_RATE);
2001 if (ret < 0) {
2002 wl1271_error("AP mgmt policy change failed %d", ret);
2003 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002004 }
2005 }
2006
Arik Nemtsove78a2872010-10-16 19:07:21 +02002007 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2008 if (ret < 0)
2009 goto out;
2010
2011 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2012 if (bss_conf->enable_beacon) {
2013 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2014 ret = wl1271_cmd_start_bss(wl);
2015 if (ret < 0)
2016 goto out;
2017
2018 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2019 wl1271_debug(DEBUG_AP, "started AP");
2020 }
2021 } else {
2022 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2023 ret = wl1271_cmd_stop_bss(wl);
2024 if (ret < 0)
2025 goto out;
2026
2027 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2028 wl1271_debug(DEBUG_AP, "stopped AP");
2029 }
2030 }
2031 }
2032
2033 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2034 if (ret < 0)
2035 goto out;
2036out:
2037 return;
2038}
2039
2040/* STA/IBSS mode changes */
2041static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2042 struct ieee80211_vif *vif,
2043 struct ieee80211_bss_conf *bss_conf,
2044 u32 changed)
2045{
2046 bool do_join = false, set_assoc = false;
2047 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2048 int ret;
2049 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2050
2051 if (is_ibss) {
2052 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2053 changed);
2054 if (ret < 0)
2055 goto out;
2056 }
2057
2058 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2059 do_join = true;
2060
2061 /* Need to update the SSID (for filtering etc) */
2062 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2063 do_join = true;
2064
2065 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002066 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2067 bss_conf->enable_beacon ? "enabled" : "disabled");
2068
2069 if (bss_conf->enable_beacon)
2070 wl->set_bss_type = BSS_TYPE_IBSS;
2071 else
2072 wl->set_bss_type = BSS_TYPE_STA_BSS;
2073 do_join = true;
2074 }
2075
Arik Nemtsove78a2872010-10-16 19:07:21 +02002076 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002077 bool enable = false;
2078 if (bss_conf->cqm_rssi_thold)
2079 enable = true;
2080 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2081 bss_conf->cqm_rssi_thold,
2082 bss_conf->cqm_rssi_hyst);
2083 if (ret < 0)
2084 goto out;
2085 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2086 }
2087
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002088 if ((changed & BSS_CHANGED_BSSID) &&
2089 /*
2090 * Now we know the correct bssid, so we send a new join command
2091 * and enable the BSSID filter
2092 */
2093 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002094 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002095
Arik Nemtsove78a2872010-10-16 19:07:21 +02002096 ret = wl1271_cmd_build_null_data(wl);
2097 if (ret < 0)
2098 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002099
Arik Nemtsove78a2872010-10-16 19:07:21 +02002100 ret = wl1271_build_qos_null_data(wl);
2101 if (ret < 0)
2102 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002103
Arik Nemtsove78a2872010-10-16 19:07:21 +02002104 /* filter out all packets not from this BSSID */
2105 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002106
Arik Nemtsove78a2872010-10-16 19:07:21 +02002107 /* Need to update the BSSID (for filtering etc) */
2108 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002109 }
2110
Arik Nemtsove78a2872010-10-16 19:07:21 +02002111 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002112 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002113 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002114 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002115 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002116 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002118 wl->ps_poll_failures = 0;
2119
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002120 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002121 * use basic rates from AP, and determine lowest rate
2122 * to use with control frames.
2123 */
2124 rates = bss_conf->basic_rates;
2125 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2126 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002127 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002128 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002129 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002130 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002131
2132 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002133 * with wl1271, we don't need to update the
2134 * beacon_int and dtim_period, because the firmware
2135 * updates it by itself when the first beacon is
2136 * received after a join.
2137 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2139 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002140 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002142 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002143 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002144 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002145 dev_kfree_skb(wl->probereq);
2146 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2147 ieoffset = offsetof(struct ieee80211_mgmt,
2148 u.probe_req.variable);
2149 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002150
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002151 /* enable the connection monitoring feature */
2152 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002154 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155
2156 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002157 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2158 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002159 enum wl1271_cmd_ps_mode mode;
2160
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002162 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002163 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002164 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002166 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002168 } else {
2169 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002170 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002171 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002172 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002173
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002174 /* free probe-request template */
2175 dev_kfree_skb(wl->probereq);
2176 wl->probereq = NULL;
2177
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002178 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002179 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002180
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002181 /* revert back to minimum rates for the current band */
2182 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002183 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002184 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002185 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002186 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002187
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002188 /* disable connection monitor features */
2189 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002190
2191 /* Disable the keep-alive feature */
2192 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002193 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002194 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002195
2196 /* restore the bssid filter and go to dummy bssid */
2197 wl1271_unjoin(wl);
2198 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199 }
2200 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002201
Arik Nemtsove78a2872010-10-16 19:07:21 +02002202 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2203 if (ret < 0)
2204 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205
Shahar Levi18357852010-10-13 16:09:41 +02002206 /*
2207 * Takes care of: New association with HT enable,
2208 * HT information change in beacon.
2209 */
2210 if (sta &&
2211 (changed & BSS_CHANGED_HT) &&
2212 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2213 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2214 if (ret < 0) {
2215 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002216 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002217 }
2218 ret = wl1271_acx_set_ht_information(wl,
2219 bss_conf->ht_operation_mode);
2220 if (ret < 0) {
2221 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002222 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002223 }
2224 }
2225 /*
2226 * Takes care of: New association without HT,
2227 * Disassociation.
2228 */
2229 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2230 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2231 if (ret < 0) {
2232 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002233 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002234 }
2235 }
2236
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002237 if (changed & BSS_CHANGED_ARP_FILTER) {
2238 __be32 addr = bss_conf->arp_addr_list[0];
2239 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2240
Eliad Pellerc5312772010-12-09 11:31:27 +02002241 if (bss_conf->arp_addr_cnt == 1 &&
2242 bss_conf->arp_filter_enabled) {
2243 /*
2244 * The template should have been configured only upon
2245 * association. however, it seems that the correct ip
2246 * isn't being set (when sending), so we have to
2247 * reconfigure the template upon every ip change.
2248 */
2249 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2250 if (ret < 0) {
2251 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002252 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002253 }
2254
2255 ret = wl1271_acx_arp_ip_filter(wl,
2256 (ACX_ARP_FILTER_ARP_FILTERING |
2257 ACX_ARP_FILTER_AUTO_ARP),
2258 addr);
2259 } else
2260 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002261
2262 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002263 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002264 }
2265
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002266 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002267 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002268 if (ret < 0) {
2269 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002270 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002271 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002272 }
2273
Arik Nemtsove78a2872010-10-16 19:07:21 +02002274out:
2275 return;
2276}
2277
2278static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2279 struct ieee80211_vif *vif,
2280 struct ieee80211_bss_conf *bss_conf,
2281 u32 changed)
2282{
2283 struct wl1271 *wl = hw->priv;
2284 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2285 int ret;
2286
2287 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2288 (int)changed);
2289
2290 mutex_lock(&wl->mutex);
2291
2292 if (unlikely(wl->state == WL1271_STATE_OFF))
2293 goto out;
2294
2295 ret = wl1271_ps_elp_wakeup(wl, false);
2296 if (ret < 0)
2297 goto out;
2298
2299 if (is_ap)
2300 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2301 else
2302 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2303
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304 wl1271_ps_elp_sleep(wl);
2305
2306out:
2307 mutex_unlock(&wl->mutex);
2308}
2309
Kalle Valoc6999d82010-02-18 13:25:41 +02002310static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2311 const struct ieee80211_tx_queue_params *params)
2312{
2313 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002314 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002315 int ret;
2316
2317 mutex_lock(&wl->mutex);
2318
2319 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2320
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002321 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2322 ret = -EAGAIN;
2323 goto out;
2324 }
2325
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002326 ret = wl1271_ps_elp_wakeup(wl, false);
2327 if (ret < 0)
2328 goto out;
2329
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002330 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002331 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2332 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002333 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002334 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002335 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002336
Kalle Valo4695dc92010-03-18 12:26:38 +02002337 if (params->uapsd)
2338 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2339 else
2340 ps_scheme = CONF_PS_SCHEME_LEGACY;
2341
Kalle Valoc6999d82010-02-18 13:25:41 +02002342 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2343 CONF_CHANNEL_TYPE_EDCF,
2344 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002345 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002346 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002347 goto out_sleep;
2348
2349out_sleep:
2350 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002351
2352out:
2353 mutex_unlock(&wl->mutex);
2354
2355 return ret;
2356}
2357
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002358static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2359{
2360
2361 struct wl1271 *wl = hw->priv;
2362 u64 mactime = ULLONG_MAX;
2363 int ret;
2364
2365 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2366
2367 mutex_lock(&wl->mutex);
2368
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002369 if (unlikely(wl->state == WL1271_STATE_OFF))
2370 goto out;
2371
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002372 ret = wl1271_ps_elp_wakeup(wl, false);
2373 if (ret < 0)
2374 goto out;
2375
2376 ret = wl1271_acx_tsf_info(wl, &mactime);
2377 if (ret < 0)
2378 goto out_sleep;
2379
2380out_sleep:
2381 wl1271_ps_elp_sleep(wl);
2382
2383out:
2384 mutex_unlock(&wl->mutex);
2385 return mactime;
2386}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387
John W. Linvilleece550d2010-07-28 16:41:06 -04002388static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2389 struct survey_info *survey)
2390{
2391 struct wl1271 *wl = hw->priv;
2392 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002393
John W. Linvilleece550d2010-07-28 16:41:06 -04002394 if (idx != 0)
2395 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002396
John W. Linvilleece550d2010-07-28 16:41:06 -04002397 survey->channel = conf->channel;
2398 survey->filled = SURVEY_INFO_NOISE_DBM;
2399 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002400
John W. Linvilleece550d2010-07-28 16:41:06 -04002401 return 0;
2402}
2403
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404/* can't be const, mac80211 writes to this */
2405static struct ieee80211_rate wl1271_rates[] = {
2406 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002407 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2408 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002410 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2411 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002412 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2413 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002414 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2415 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002416 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2417 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002418 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2419 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002420 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2421 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002422 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2423 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002424 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002425 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2426 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002428 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2429 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002431 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2432 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002434 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2435 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002436 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002437 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2438 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002440 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2441 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002442 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002443 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2444 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445};
2446
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002447/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002449 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002450 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002451 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2452 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2453 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002454 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002455 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2456 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2457 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002458 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002459 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2460 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2461 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002462};
2463
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002464/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002465static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002466 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002467 7, /* CONF_HW_RXTX_RATE_MCS7 */
2468 6, /* CONF_HW_RXTX_RATE_MCS6 */
2469 5, /* CONF_HW_RXTX_RATE_MCS5 */
2470 4, /* CONF_HW_RXTX_RATE_MCS4 */
2471 3, /* CONF_HW_RXTX_RATE_MCS3 */
2472 2, /* CONF_HW_RXTX_RATE_MCS2 */
2473 1, /* CONF_HW_RXTX_RATE_MCS1 */
2474 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002475
2476 11, /* CONF_HW_RXTX_RATE_54 */
2477 10, /* CONF_HW_RXTX_RATE_48 */
2478 9, /* CONF_HW_RXTX_RATE_36 */
2479 8, /* CONF_HW_RXTX_RATE_24 */
2480
2481 /* TI-specific rate */
2482 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2483
2484 7, /* CONF_HW_RXTX_RATE_18 */
2485 6, /* CONF_HW_RXTX_RATE_12 */
2486 3, /* CONF_HW_RXTX_RATE_11 */
2487 5, /* CONF_HW_RXTX_RATE_9 */
2488 4, /* CONF_HW_RXTX_RATE_6 */
2489 2, /* CONF_HW_RXTX_RATE_5_5 */
2490 1, /* CONF_HW_RXTX_RATE_2 */
2491 0 /* CONF_HW_RXTX_RATE_1 */
2492};
2493
Shahar Levie8b03a22010-10-13 16:09:39 +02002494/* 11n STA capabilities */
2495#define HW_RX_HIGHEST_RATE 72
2496
Shahar Levi00d20102010-11-08 11:20:10 +00002497#ifdef CONFIG_WL12XX_HT
2498#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002499 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2500 .ht_supported = true, \
2501 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2502 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2503 .mcs = { \
2504 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2505 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2506 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2507 }, \
2508}
Shahar Levi18357852010-10-13 16:09:41 +02002509#else
Shahar Levi00d20102010-11-08 11:20:10 +00002510#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002511 .ht_supported = false, \
2512}
2513#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515/* can't be const, mac80211 writes to this */
2516static struct ieee80211_supported_band wl1271_band_2ghz = {
2517 .channels = wl1271_channels,
2518 .n_channels = ARRAY_SIZE(wl1271_channels),
2519 .bitrates = wl1271_rates,
2520 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002521 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002522};
2523
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002524/* 5 GHz data rates for WL1273 */
2525static struct ieee80211_rate wl1271_rates_5ghz[] = {
2526 { .bitrate = 60,
2527 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2528 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2529 { .bitrate = 90,
2530 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2531 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2532 { .bitrate = 120,
2533 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2534 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2535 { .bitrate = 180,
2536 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2537 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2538 { .bitrate = 240,
2539 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2540 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2541 { .bitrate = 360,
2542 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2543 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2544 { .bitrate = 480,
2545 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2546 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2547 { .bitrate = 540,
2548 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2549 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2550};
2551
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002552/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002553static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002554 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002555 { .hw_value = 8, .center_freq = 5040},
2556 { .hw_value = 9, .center_freq = 5045},
2557 { .hw_value = 11, .center_freq = 5055},
2558 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002559 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002560 { .hw_value = 34, .center_freq = 5170},
2561 { .hw_value = 36, .center_freq = 5180},
2562 { .hw_value = 38, .center_freq = 5190},
2563 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002564 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002565 { .hw_value = 44, .center_freq = 5220},
2566 { .hw_value = 46, .center_freq = 5230},
2567 { .hw_value = 48, .center_freq = 5240},
2568 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002569 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002570 { .hw_value = 60, .center_freq = 5300},
2571 { .hw_value = 64, .center_freq = 5320},
2572 { .hw_value = 100, .center_freq = 5500},
2573 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002574 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002575 { .hw_value = 112, .center_freq = 5560},
2576 { .hw_value = 116, .center_freq = 5580},
2577 { .hw_value = 120, .center_freq = 5600},
2578 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002579 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002580 { .hw_value = 132, .center_freq = 5660},
2581 { .hw_value = 136, .center_freq = 5680},
2582 { .hw_value = 140, .center_freq = 5700},
2583 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002584 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002585 { .hw_value = 157, .center_freq = 5785},
2586 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002587 { .hw_value = 165, .center_freq = 5825},
2588};
2589
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002590/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002591static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002592 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002593 7, /* CONF_HW_RXTX_RATE_MCS7 */
2594 6, /* CONF_HW_RXTX_RATE_MCS6 */
2595 5, /* CONF_HW_RXTX_RATE_MCS5 */
2596 4, /* CONF_HW_RXTX_RATE_MCS4 */
2597 3, /* CONF_HW_RXTX_RATE_MCS3 */
2598 2, /* CONF_HW_RXTX_RATE_MCS2 */
2599 1, /* CONF_HW_RXTX_RATE_MCS1 */
2600 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002601
2602 7, /* CONF_HW_RXTX_RATE_54 */
2603 6, /* CONF_HW_RXTX_RATE_48 */
2604 5, /* CONF_HW_RXTX_RATE_36 */
2605 4, /* CONF_HW_RXTX_RATE_24 */
2606
2607 /* TI-specific rate */
2608 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2609
2610 3, /* CONF_HW_RXTX_RATE_18 */
2611 2, /* CONF_HW_RXTX_RATE_12 */
2612 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2613 1, /* CONF_HW_RXTX_RATE_9 */
2614 0, /* CONF_HW_RXTX_RATE_6 */
2615 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2616 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2617 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2618};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002619
2620static struct ieee80211_supported_band wl1271_band_5ghz = {
2621 .channels = wl1271_channels_5ghz,
2622 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2623 .bitrates = wl1271_rates_5ghz,
2624 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002625 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002626};
2627
Tobias Klausera0ea9492010-05-20 10:38:11 +02002628static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002629 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2630 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2631};
2632
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002633static const struct ieee80211_ops wl1271_ops = {
2634 .start = wl1271_op_start,
2635 .stop = wl1271_op_stop,
2636 .add_interface = wl1271_op_add_interface,
2637 .remove_interface = wl1271_op_remove_interface,
2638 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002639 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640 .configure_filter = wl1271_op_configure_filter,
2641 .tx = wl1271_op_tx,
2642 .set_key = wl1271_op_set_key,
2643 .hw_scan = wl1271_op_hw_scan,
2644 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002645 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002647 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002648 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002649 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002650 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002651};
2652
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002653
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002654u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002655{
2656 u8 idx;
2657
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002658 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002659
2660 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2661 wl1271_error("Illegal RX rate from HW: %d", rate);
2662 return 0;
2663 }
2664
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002665 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002666 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2667 wl1271_error("Unsupported RX rate from HW: %d", rate);
2668 return 0;
2669 }
2670
2671 return idx;
2672}
2673
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002674static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2675 struct device_attribute *attr,
2676 char *buf)
2677{
2678 struct wl1271 *wl = dev_get_drvdata(dev);
2679 ssize_t len;
2680
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002681 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002682
2683 mutex_lock(&wl->mutex);
2684 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2685 wl->sg_enabled);
2686 mutex_unlock(&wl->mutex);
2687
2688 return len;
2689
2690}
2691
2692static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2693 struct device_attribute *attr,
2694 const char *buf, size_t count)
2695{
2696 struct wl1271 *wl = dev_get_drvdata(dev);
2697 unsigned long res;
2698 int ret;
2699
2700 ret = strict_strtoul(buf, 10, &res);
2701
2702 if (ret < 0) {
2703 wl1271_warning("incorrect value written to bt_coex_mode");
2704 return count;
2705 }
2706
2707 mutex_lock(&wl->mutex);
2708
2709 res = !!res;
2710
2711 if (res == wl->sg_enabled)
2712 goto out;
2713
2714 wl->sg_enabled = res;
2715
2716 if (wl->state == WL1271_STATE_OFF)
2717 goto out;
2718
2719 ret = wl1271_ps_elp_wakeup(wl, false);
2720 if (ret < 0)
2721 goto out;
2722
2723 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2724 wl1271_ps_elp_sleep(wl);
2725
2726 out:
2727 mutex_unlock(&wl->mutex);
2728 return count;
2729}
2730
2731static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2732 wl1271_sysfs_show_bt_coex_state,
2733 wl1271_sysfs_store_bt_coex_state);
2734
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002735static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2736 struct device_attribute *attr,
2737 char *buf)
2738{
2739 struct wl1271 *wl = dev_get_drvdata(dev);
2740 ssize_t len;
2741
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002742 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002743
2744 mutex_lock(&wl->mutex);
2745 if (wl->hw_pg_ver >= 0)
2746 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2747 else
2748 len = snprintf(buf, len, "n/a\n");
2749 mutex_unlock(&wl->mutex);
2750
2751 return len;
2752}
2753
2754static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2755 wl1271_sysfs_show_hw_pg_ver, NULL);
2756
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002757int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758{
2759 int ret;
2760
2761 if (wl->mac80211_registered)
2762 return 0;
2763
2764 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2765
2766 ret = ieee80211_register_hw(wl->hw);
2767 if (ret < 0) {
2768 wl1271_error("unable to register mac80211 hw: %d", ret);
2769 return ret;
2770 }
2771
2772 wl->mac80211_registered = true;
2773
Eliad Pellerd60080a2010-11-24 12:53:16 +02002774 wl1271_debugfs_init(wl);
2775
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002776 register_netdevice_notifier(&wl1271_dev_notifier);
2777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002778 wl1271_notice("loaded");
2779
2780 return 0;
2781}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002782EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002783
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002784void wl1271_unregister_hw(struct wl1271 *wl)
2785{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002786 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002787 ieee80211_unregister_hw(wl->hw);
2788 wl->mac80211_registered = false;
2789
2790}
2791EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2792
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002793int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002794{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002795 static const u32 cipher_suites[] = {
2796 WLAN_CIPHER_SUITE_WEP40,
2797 WLAN_CIPHER_SUITE_WEP104,
2798 WLAN_CIPHER_SUITE_TKIP,
2799 WLAN_CIPHER_SUITE_CCMP,
2800 WL1271_CIPHER_SUITE_GEM,
2801 };
2802
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002803 /* The tx descriptor buffer and the TKIP space. */
2804 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2805 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002806
2807 /* unit us */
2808 /* FIXME: find a proper value */
2809 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002810 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811
2812 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002813 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002814 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002815 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002816 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002817 IEEE80211_HW_CONNECTION_MONITOR |
2818 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002820 wl->hw->wiphy->cipher_suites = cipher_suites;
2821 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2822
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002823 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2824 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02002826 /*
2827 * Maximum length of elements in scanning probe request templates
2828 * should be the maximum length possible for a template, without
2829 * the IEEE80211 header of the template
2830 */
2831 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
2832 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002833 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002834 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002835
Kalle Valo12bd8942010-03-18 12:26:33 +02002836 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002837 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002838
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002839 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2840
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002841 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002842
2843 return 0;
2844}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002845EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002847#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002848
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002849struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002850{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002851 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002852 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002853 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002854 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002855 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002856
2857 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2858 if (!hw) {
2859 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002860 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002861 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002862 }
2863
Julia Lawall929ebd32010-05-15 23:16:39 +02002864 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002865 if (!plat_dev) {
2866 wl1271_error("could not allocate platform_device");
2867 ret = -ENOMEM;
2868 goto err_plat_alloc;
2869 }
2870
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002871 wl = hw->priv;
2872 memset(wl, 0, sizeof(*wl));
2873
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002874 INIT_LIST_HEAD(&wl->list);
2875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002876 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002877 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002878
Juuso Oikarinen6742f552010-12-13 09:52:37 +02002879 for (i = 0; i < NUM_TX_QUEUES; i++)
2880 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002881
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002882 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002883 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002884 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2885 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2886 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2887 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002888 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002889 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002890 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02002892 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
2893 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002894 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002895 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002896 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002897 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002898 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2899 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002900 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002901 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002902 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002903 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002904 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905
Ido Yariv25eeb9e2010-10-12 16:20:06 +02002906 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002907 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002908 wl->tx_frames[i] = NULL;
2909
2910 spin_lock_init(&wl->wl_lock);
2911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 wl->state = WL1271_STATE_OFF;
2913 mutex_init(&wl->mutex);
2914
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002915 /* Apply default driver configuration. */
2916 wl1271_conf_init(wl);
2917
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002918 order = get_order(WL1271_AGGR_BUFFER_SIZE);
2919 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
2920 if (!wl->aggr_buf) {
2921 ret = -ENOMEM;
2922 goto err_hw;
2923 }
2924
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002925 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002926 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002927 if (ret) {
2928 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002929 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002930 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002931 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002932
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002933 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002934 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002935 if (ret < 0) {
2936 wl1271_error("failed to create sysfs file bt_coex_state");
2937 goto err_platform;
2938 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002939
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002940 /* Create sysfs file to get HW PG version */
2941 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2942 if (ret < 0) {
2943 wl1271_error("failed to create sysfs file hw_pg_ver");
2944 goto err_bt_coex_state;
2945 }
2946
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002947 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002948
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002949err_bt_coex_state:
2950 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2951
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002952err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002953 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002954
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002955err_aggr:
2956 free_pages((unsigned long)wl->aggr_buf, order);
2957
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002958err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002959 wl1271_debugfs_exit(wl);
2960 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002961
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002962err_plat_alloc:
2963 ieee80211_free_hw(hw);
2964
2965err_hw_alloc:
2966
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002967 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002968}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002969EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002970
2971int wl1271_free_hw(struct wl1271 *wl)
2972{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002973 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002974 free_pages((unsigned long)wl->aggr_buf,
2975 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002976 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002977
2978 wl1271_debugfs_exit(wl);
2979
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002980 vfree(wl->fw);
2981 wl->fw = NULL;
2982 kfree(wl->nvs);
2983 wl->nvs = NULL;
2984
2985 kfree(wl->fw_status);
2986 kfree(wl->tx_res_if);
2987
2988 ieee80211_free_hw(wl->hw);
2989
2990 return 0;
2991}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002992EXPORT_SYMBOL_GPL(wl1271_free_hw);
2993
Eliad Peller17c17552010-12-12 12:15:35 +02002994u32 wl12xx_debug_level;
2995EXPORT_SYMBOL_GPL(wl12xx_debug_level);
2996module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
2997MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
2998
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002999MODULE_LICENSE("GPL");
3000MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3001MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");