blob: 739fee640528e1dc17f58ba3db96d68017a1f5aa [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;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001195 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001196
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001197 for (i = 0; i < NUM_TX_QUEUES; i++)
1198 wl->tx_blocks_freed[i] = 0;
1199
1200 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001201
1202 kfree(wl->fw_status);
1203 wl->fw_status = NULL;
1204 kfree(wl->tx_res_if);
1205 wl->tx_res_if = NULL;
1206 kfree(wl->target_mem_map);
1207 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001208}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001209
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001210static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1211 struct ieee80211_vif *vif)
1212{
1213 struct wl1271 *wl = hw->priv;
1214
1215 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001216 /*
1217 * wl->vif can be null here if someone shuts down the interface
1218 * just when hardware recovery has been started.
1219 */
1220 if (wl->vif) {
1221 WARN_ON(wl->vif != vif);
1222 __wl1271_op_remove_interface(wl);
1223 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001224
Juuso Oikarinen67353292010-11-18 15:19:02 +02001225 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001226 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227}
1228
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001229static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1230{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001231 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001232
1233 /* combine requested filters with current filter config */
1234 filters = wl->filters | filters;
1235
1236 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1237
1238 if (filters & FIF_PROMISC_IN_BSS) {
1239 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1240 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1241 wl->rx_config |= CFG_BSSID_FILTER_EN;
1242 }
1243 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1244 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1245 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1246 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1247 }
1248 if (filters & FIF_OTHER_BSS) {
1249 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1250 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1251 }
1252 if (filters & FIF_CONTROL) {
1253 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1254 wl->rx_filter |= CFG_RX_CTL_EN;
1255 }
1256 if (filters & FIF_FCSFAIL) {
1257 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1258 wl->rx_filter |= CFG_RX_FCS_ERROR;
1259 }
1260}
1261
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001262static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001263{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001264 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001265 /* we need to use a dummy BSSID for now */
1266 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1267 0xad, 0xbe, 0xef };
1268
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001269 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1270
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001271 /* pass through frames from all BSS */
1272 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1273
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001274 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001275 if (ret < 0)
1276 goto out;
1277
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001278 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001279
1280out:
1281 return ret;
1282}
1283
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001284static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001285{
1286 int ret;
1287
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001288 /*
1289 * One of the side effects of the JOIN command is that is clears
1290 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1291 * to a WPA/WPA2 access point will therefore kill the data-path.
1292 * Currently there is no supported scenario for JOIN during
1293 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1294 * must be handled somehow.
1295 *
1296 */
1297 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1298 wl1271_info("JOIN while associated.");
1299
1300 if (set_assoc)
1301 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1302
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001303 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1304 if (ret < 0)
1305 goto out;
1306
1307 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1308
1309 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1310 goto out;
1311
1312 /*
1313 * The join command disable the keep-alive mode, shut down its process,
1314 * and also clear the template config, so we need to reset it all after
1315 * the join. The acx_aid starts the keep-alive process, and the order
1316 * of the commands below is relevant.
1317 */
1318 ret = wl1271_acx_keep_alive_mode(wl, true);
1319 if (ret < 0)
1320 goto out;
1321
1322 ret = wl1271_acx_aid(wl, wl->aid);
1323 if (ret < 0)
1324 goto out;
1325
1326 ret = wl1271_cmd_build_klv_null_data(wl);
1327 if (ret < 0)
1328 goto out;
1329
1330 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1331 ACX_KEEP_ALIVE_TPL_VALID);
1332 if (ret < 0)
1333 goto out;
1334
1335out:
1336 return ret;
1337}
1338
1339static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001340{
1341 int ret;
1342
1343 /* to stop listening to a channel, we disconnect */
1344 ret = wl1271_cmd_disconnect(wl);
1345 if (ret < 0)
1346 goto out;
1347
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001348 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001349 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001350
1351 /* stop filterting packets based on bssid */
1352 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001353
1354out:
1355 return ret;
1356}
1357
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001358static void wl1271_set_band_rate(struct wl1271 *wl)
1359{
1360 if (wl->band == IEEE80211_BAND_2GHZ)
1361 wl->basic_rate_set = wl->conf.tx.basic_rate;
1362 else
1363 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1364}
1365
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001366static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001367{
1368 int ret;
1369
1370 if (idle) {
1371 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1372 ret = wl1271_unjoin(wl);
1373 if (ret < 0)
1374 goto out;
1375 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001376 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001377 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001378 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001379 if (ret < 0)
1380 goto out;
1381 ret = wl1271_acx_keep_alive_config(
1382 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1383 ACX_KEEP_ALIVE_TPL_INVALID);
1384 if (ret < 0)
1385 goto out;
1386 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1387 } else {
1388 /* increment the session counter */
1389 wl->session_counter++;
1390 if (wl->session_counter >= SESSION_COUNTER_MAX)
1391 wl->session_counter = 0;
1392 ret = wl1271_dummy_join(wl);
1393 if (ret < 0)
1394 goto out;
1395 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1396 }
1397
1398out:
1399 return ret;
1400}
1401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1403{
1404 struct wl1271 *wl = hw->priv;
1405 struct ieee80211_conf *conf = &hw->conf;
1406 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001407 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408
1409 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1410
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001411 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1412 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413 channel,
1414 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001415 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001416 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1417 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001419 /*
1420 * mac80211 will go to idle nearly immediately after transmitting some
1421 * frames, such as the deauth. To make sure those frames reach the air,
1422 * wait here until the TX queue is fully flushed.
1423 */
1424 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1425 (conf->flags & IEEE80211_CONF_IDLE))
1426 wl1271_tx_flush(wl);
1427
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428 mutex_lock(&wl->mutex);
1429
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001430 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1431 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001432 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001433 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001434
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001435 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1436
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437 ret = wl1271_ps_elp_wakeup(wl, false);
1438 if (ret < 0)
1439 goto out;
1440
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001441 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001442 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1443 ((wl->band != conf->channel->band) ||
1444 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001445 wl->band = conf->channel->band;
1446 wl->channel = channel;
1447
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001448 if (!is_ap) {
1449 /*
1450 * FIXME: the mac80211 should really provide a fixed
1451 * rate to use here. for now, just use the smallest
1452 * possible rate for the band as a fixed rate for
1453 * association frames and other control messages.
1454 */
1455 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1456 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001457
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001458 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1459 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001460 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001461 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001462 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001463
1464 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1465 ret = wl1271_join(wl, false);
1466 if (ret < 0)
1467 wl1271_warning("cmd join on channel "
1468 "failed %d", ret);
1469 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001470 }
1471 }
1472
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001473 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1474 ret = wl1271_sta_handle_idle(wl,
1475 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001476 if (ret < 0)
1477 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 }
1479
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001480 /*
1481 * if mac80211 changes the PSM mode, make sure the mode is not
1482 * incorrectly changed after the pspoll failure active window.
1483 */
1484 if (changed & IEEE80211_CONF_CHANGE_PS)
1485 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1486
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001487 if (conf->flags & IEEE80211_CONF_PS &&
1488 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1489 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001490
1491 /*
1492 * We enter PSM only if we're already associated.
1493 * If we're not, we'll enter it when joining an SSID,
1494 * through the bss_info_changed() hook.
1495 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001496 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001497 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001498 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001499 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001500 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001502 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001503 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001505 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001507 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001508 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001509 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510 }
1511
1512 if (conf->power_level != wl->power_level) {
1513 ret = wl1271_acx_tx_power(wl, conf->power_level);
1514 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001515 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516
1517 wl->power_level = conf->power_level;
1518 }
1519
1520out_sleep:
1521 wl1271_ps_elp_sleep(wl);
1522
1523out:
1524 mutex_unlock(&wl->mutex);
1525
1526 return ret;
1527}
1528
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001529struct wl1271_filter_params {
1530 bool enabled;
1531 int mc_list_length;
1532 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1533};
1534
Jiri Pirko22bedad2010-04-01 21:22:57 +00001535static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1536 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001537{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001538 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001539 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001540 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001541
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001542 if (unlikely(wl->state == WL1271_STATE_OFF))
1543 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001544
Juuso Oikarinen74441132009-10-13 12:47:53 +03001545 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001546 if (!fp) {
1547 wl1271_error("Out of memory setting filters.");
1548 return 0;
1549 }
1550
1551 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001552 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001553 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1554 fp->enabled = false;
1555 } else {
1556 fp->enabled = true;
1557 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001558 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001559 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001560 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001561 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001562 }
1563
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001564 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001565}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001567#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1568 FIF_ALLMULTI | \
1569 FIF_FCSFAIL | \
1570 FIF_BCN_PRBRESP_PROMISC | \
1571 FIF_CONTROL | \
1572 FIF_OTHER_BSS)
1573
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1575 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001576 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001578 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001580 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001581
Arik Nemtsov7d057862010-10-16 19:25:35 +02001582 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1583 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001585 mutex_lock(&wl->mutex);
1586
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001587 *total &= WL1271_SUPPORTED_FILTERS;
1588 changed &= WL1271_SUPPORTED_FILTERS;
1589
1590 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001591 goto out;
1592
1593 ret = wl1271_ps_elp_wakeup(wl, false);
1594 if (ret < 0)
1595 goto out;
1596
Arik Nemtsov7d057862010-10-16 19:25:35 +02001597 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1598 if (*total & FIF_ALLMULTI)
1599 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1600 else if (fp)
1601 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1602 fp->mc_list,
1603 fp->mc_list_length);
1604 if (ret < 0)
1605 goto out_sleep;
1606 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001608 /* determine, whether supported filter values have changed */
1609 if (changed == 0)
1610 goto out_sleep;
1611
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001612 /* configure filters */
1613 wl->filters = *total;
1614 wl1271_configure_filters(wl, 0);
1615
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001616 /* apply configured filters */
1617 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1618 if (ret < 0)
1619 goto out_sleep;
1620
1621out_sleep:
1622 wl1271_ps_elp_sleep(wl);
1623
1624out:
1625 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001626 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001627}
1628
1629static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1630 struct ieee80211_vif *vif,
1631 struct ieee80211_sta *sta,
1632 struct ieee80211_key_conf *key_conf)
1633{
1634 struct wl1271 *wl = hw->priv;
1635 const u8 *addr;
1636 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001637 u32 tx_seq_32 = 0;
1638 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001639 u8 key_type;
1640
1641 static const u8 bcast_addr[ETH_ALEN] =
1642 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1643
1644 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1645
1646 addr = sta ? sta->addr : bcast_addr;
1647
1648 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1649 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1650 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001651 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001652 key_conf->keylen, key_conf->flags);
1653 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1654
1655 if (is_zero_ether_addr(addr)) {
1656 /* We dont support TX only encryption */
1657 ret = -EOPNOTSUPP;
1658 goto out;
1659 }
1660
1661 mutex_lock(&wl->mutex);
1662
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001663 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1664 ret = -EAGAIN;
1665 goto out_unlock;
1666 }
1667
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668 ret = wl1271_ps_elp_wakeup(wl, false);
1669 if (ret < 0)
1670 goto out_unlock;
1671
Johannes Berg97359d12010-08-10 09:46:38 +02001672 switch (key_conf->cipher) {
1673 case WLAN_CIPHER_SUITE_WEP40:
1674 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 key_type = KEY_WEP;
1676
1677 key_conf->hw_key_idx = key_conf->keyidx;
1678 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001679 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680 key_type = KEY_TKIP;
1681
1682 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001683 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1684 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001686 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 key_type = KEY_AES;
1688
1689 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001690 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1691 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001692 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001693 case WL1271_CIPHER_SUITE_GEM:
1694 key_type = KEY_GEM;
1695 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1696 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1697 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001699 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700
1701 ret = -EOPNOTSUPP;
1702 goto out_sleep;
1703 }
1704
1705 switch (cmd) {
1706 case SET_KEY:
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001707 ret = wl1271_cmd_set_sta_key(wl, KEY_ADD_OR_REPLACE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 key_conf->keyidx, key_type,
1709 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001710 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001711 if (ret < 0) {
1712 wl1271_error("Could not add or replace key");
1713 goto out_sleep;
1714 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001715
1716 /* the default WEP key needs to be configured at least once */
1717 if (key_type == KEY_WEP) {
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001718 ret = wl1271_cmd_set_sta_default_wep_key(wl,
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001719 wl->default_key);
1720 if (ret < 0)
1721 goto out_sleep;
1722 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 break;
1724
1725 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001726 /* The wl1271 does not allow to remove unicast keys - they
1727 will be cleared automatically on next CMD_JOIN. Ignore the
1728 request silently, as we dont want the mac80211 to emit
1729 an error message. */
1730 if (!is_broadcast_ether_addr(addr))
1731 break;
1732
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001733 ret = wl1271_cmd_set_sta_key(wl, KEY_REMOVE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734 key_conf->keyidx, key_type,
1735 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001736 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001737 if (ret < 0) {
1738 wl1271_error("Could not remove key");
1739 goto out_sleep;
1740 }
1741 break;
1742
1743 default:
1744 wl1271_error("Unsupported key cmd 0x%x", cmd);
1745 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001746 break;
1747 }
1748
1749out_sleep:
1750 wl1271_ps_elp_sleep(wl);
1751
1752out_unlock:
1753 mutex_unlock(&wl->mutex);
1754
1755out:
1756 return ret;
1757}
1758
1759static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001760 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001761 struct cfg80211_scan_request *req)
1762{
1763 struct wl1271 *wl = hw->priv;
1764 int ret;
1765 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001766 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767
1768 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1769
1770 if (req->n_ssids) {
1771 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001772 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773 }
1774
1775 mutex_lock(&wl->mutex);
1776
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001777 if (wl->state == WL1271_STATE_OFF) {
1778 /*
1779 * We cannot return -EBUSY here because cfg80211 will expect
1780 * a call to ieee80211_scan_completed if we do - in this case
1781 * there won't be any call.
1782 */
1783 ret = -EAGAIN;
1784 goto out;
1785 }
1786
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001787 ret = wl1271_ps_elp_wakeup(wl, false);
1788 if (ret < 0)
1789 goto out;
1790
Luciano Coelho5924f892010-08-04 03:46:22 +03001791 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792
1793 wl1271_ps_elp_sleep(wl);
1794
1795out:
1796 mutex_unlock(&wl->mutex);
1797
1798 return ret;
1799}
1800
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001801static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1802{
1803 struct wl1271 *wl = hw->priv;
1804 int ret = 0;
1805
1806 mutex_lock(&wl->mutex);
1807
1808 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1809 ret = -EAGAIN;
1810 goto out;
1811 }
1812
1813 ret = wl1271_ps_elp_wakeup(wl, false);
1814 if (ret < 0)
1815 goto out;
1816
1817 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1818 if (ret < 0)
1819 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1820
1821 wl1271_ps_elp_sleep(wl);
1822
1823out:
1824 mutex_unlock(&wl->mutex);
1825
1826 return ret;
1827}
1828
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1830{
1831 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001832 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833
1834 mutex_lock(&wl->mutex);
1835
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001836 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1837 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001838 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001839 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 ret = wl1271_ps_elp_wakeup(wl, false);
1842 if (ret < 0)
1843 goto out;
1844
1845 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1846 if (ret < 0)
1847 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1848
1849 wl1271_ps_elp_sleep(wl);
1850
1851out:
1852 mutex_unlock(&wl->mutex);
1853
1854 return ret;
1855}
1856
Arik Nemtsove78a2872010-10-16 19:07:21 +02001857static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001858 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001859{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001860 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001861
1862 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001863 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001864 if (ptr[0] == WLAN_EID_SSID) {
1865 wl->ssid_len = ptr[1];
1866 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02001867 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001868 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001869 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001870 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02001871
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001872 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02001873 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001874}
1875
Arik Nemtsove78a2872010-10-16 19:07:21 +02001876static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
1877 struct ieee80211_bss_conf *bss_conf,
1878 u32 changed)
1879{
1880 int ret = 0;
1881
1882 if (changed & BSS_CHANGED_ERP_SLOT) {
1883 if (bss_conf->use_short_slot)
1884 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1885 else
1886 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1887 if (ret < 0) {
1888 wl1271_warning("Set slot time failed %d", ret);
1889 goto out;
1890 }
1891 }
1892
1893 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1894 if (bss_conf->use_short_preamble)
1895 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1896 else
1897 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1898 }
1899
1900 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1901 if (bss_conf->use_cts_prot)
1902 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1903 else
1904 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1905 if (ret < 0) {
1906 wl1271_warning("Set ctsprotect failed %d", ret);
1907 goto out;
1908 }
1909 }
1910
1911out:
1912 return ret;
1913}
1914
1915static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
1916 struct ieee80211_vif *vif,
1917 struct ieee80211_bss_conf *bss_conf,
1918 u32 changed)
1919{
1920 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1921 int ret = 0;
1922
1923 if ((changed & BSS_CHANGED_BEACON_INT)) {
1924 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
1925 bss_conf->beacon_int);
1926
1927 wl->beacon_int = bss_conf->beacon_int;
1928 }
1929
1930 if ((changed & BSS_CHANGED_BEACON)) {
1931 struct ieee80211_hdr *hdr;
1932 int ieoffset = offsetof(struct ieee80211_mgmt,
1933 u.beacon.variable);
1934 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
1935 u16 tmpl_id;
1936
1937 if (!beacon)
1938 goto out;
1939
1940 wl1271_debug(DEBUG_MASTER, "beacon updated");
1941
1942 ret = wl1271_ssid_set(wl, beacon, ieoffset);
1943 if (ret < 0) {
1944 dev_kfree_skb(beacon);
1945 goto out;
1946 }
1947 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
1948 CMD_TEMPL_BEACON;
1949 ret = wl1271_cmd_template_set(wl, tmpl_id,
1950 beacon->data,
1951 beacon->len, 0,
1952 wl1271_tx_min_rate_get(wl));
1953 if (ret < 0) {
1954 dev_kfree_skb(beacon);
1955 goto out;
1956 }
1957
1958 hdr = (struct ieee80211_hdr *) beacon->data;
1959 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1960 IEEE80211_STYPE_PROBE_RESP);
1961
1962 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
1963 CMD_TEMPL_PROBE_RESPONSE;
1964 ret = wl1271_cmd_template_set(wl,
1965 tmpl_id,
1966 beacon->data,
1967 beacon->len, 0,
1968 wl1271_tx_min_rate_get(wl));
1969 dev_kfree_skb(beacon);
1970 if (ret < 0)
1971 goto out;
1972 }
1973
1974out:
1975 return ret;
1976}
1977
1978/* AP mode changes */
1979static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 struct ieee80211_vif *vif,
1981 struct ieee80211_bss_conf *bss_conf,
1982 u32 changed)
1983{
Arik Nemtsove78a2872010-10-16 19:07:21 +02001984 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985
Arik Nemtsove78a2872010-10-16 19:07:21 +02001986 if ((changed & BSS_CHANGED_BASIC_RATES)) {
1987 u32 rates = bss_conf->basic_rates;
1988 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
Arik Nemtsove78a2872010-10-16 19:07:21 +02001990 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
1991 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1992 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
1993 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994
Arik Nemtsove78a2872010-10-16 19:07:21 +02001995 /* update the AP management rate policy with the new rates */
1996 mgmt_rc.enabled_rates = wl->basic_rate_set;
1997 mgmt_rc.long_retry_limit = 10;
1998 mgmt_rc.short_retry_limit = 10;
1999 mgmt_rc.aflags = 0;
2000 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2001 ACX_TX_AP_MODE_MGMT_RATE);
2002 if (ret < 0) {
2003 wl1271_error("AP mgmt policy change failed %d", ret);
2004 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002005 }
2006 }
2007
Arik Nemtsove78a2872010-10-16 19:07:21 +02002008 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2009 if (ret < 0)
2010 goto out;
2011
2012 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2013 if (bss_conf->enable_beacon) {
2014 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2015 ret = wl1271_cmd_start_bss(wl);
2016 if (ret < 0)
2017 goto out;
2018
2019 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2020 wl1271_debug(DEBUG_AP, "started AP");
2021 }
2022 } else {
2023 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2024 ret = wl1271_cmd_stop_bss(wl);
2025 if (ret < 0)
2026 goto out;
2027
2028 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2029 wl1271_debug(DEBUG_AP, "stopped AP");
2030 }
2031 }
2032 }
2033
2034 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2035 if (ret < 0)
2036 goto out;
2037out:
2038 return;
2039}
2040
2041/* STA/IBSS mode changes */
2042static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2043 struct ieee80211_vif *vif,
2044 struct ieee80211_bss_conf *bss_conf,
2045 u32 changed)
2046{
2047 bool do_join = false, set_assoc = false;
2048 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2049 int ret;
2050 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2051
2052 if (is_ibss) {
2053 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2054 changed);
2055 if (ret < 0)
2056 goto out;
2057 }
2058
2059 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2060 do_join = true;
2061
2062 /* Need to update the SSID (for filtering etc) */
2063 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2064 do_join = true;
2065
2066 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002067 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2068 bss_conf->enable_beacon ? "enabled" : "disabled");
2069
2070 if (bss_conf->enable_beacon)
2071 wl->set_bss_type = BSS_TYPE_IBSS;
2072 else
2073 wl->set_bss_type = BSS_TYPE_STA_BSS;
2074 do_join = true;
2075 }
2076
Arik Nemtsove78a2872010-10-16 19:07:21 +02002077 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002078 bool enable = false;
2079 if (bss_conf->cqm_rssi_thold)
2080 enable = true;
2081 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2082 bss_conf->cqm_rssi_thold,
2083 bss_conf->cqm_rssi_hyst);
2084 if (ret < 0)
2085 goto out;
2086 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2087 }
2088
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002089 if ((changed & BSS_CHANGED_BSSID) &&
2090 /*
2091 * Now we know the correct bssid, so we send a new join command
2092 * and enable the BSSID filter
2093 */
2094 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002095 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002096
Arik Nemtsove78a2872010-10-16 19:07:21 +02002097 ret = wl1271_cmd_build_null_data(wl);
2098 if (ret < 0)
2099 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002100
Arik Nemtsove78a2872010-10-16 19:07:21 +02002101 ret = wl1271_build_qos_null_data(wl);
2102 if (ret < 0)
2103 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002104
Arik Nemtsove78a2872010-10-16 19:07:21 +02002105 /* filter out all packets not from this BSSID */
2106 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002107
Arik Nemtsove78a2872010-10-16 19:07:21 +02002108 /* Need to update the BSSID (for filtering etc) */
2109 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002110 }
2111
Arik Nemtsove78a2872010-10-16 19:07:21 +02002112 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002114 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002115 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002116 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002117 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002118
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002119 wl->ps_poll_failures = 0;
2120
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002121 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002122 * use basic rates from AP, and determine lowest rate
2123 * to use with control frames.
2124 */
2125 rates = bss_conf->basic_rates;
2126 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2127 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002128 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002129 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002130 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002131 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002132
2133 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002134 * with wl1271, we don't need to update the
2135 * beacon_int and dtim_period, because the firmware
2136 * updates it by itself when the first beacon is
2137 * received after a join.
2138 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002139 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2140 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002141 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002143 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002144 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002145 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002146 dev_kfree_skb(wl->probereq);
2147 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2148 ieoffset = offsetof(struct ieee80211_mgmt,
2149 u.probe_req.variable);
2150 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002151
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002152 /* enable the connection monitoring feature */
2153 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156
2157 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002158 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2159 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002160 enum wl1271_cmd_ps_mode mode;
2161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002163 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002164 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002165 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002167 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002169 } else {
2170 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002171 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002172 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002173 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002174
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002175 /* free probe-request template */
2176 dev_kfree_skb(wl->probereq);
2177 wl->probereq = NULL;
2178
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002179 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002180 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002181
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002182 /* revert back to minimum rates for the current band */
2183 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002184 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002185 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002186 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002187 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002188
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002189 /* disable connection monitor features */
2190 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002191
2192 /* Disable the keep-alive feature */
2193 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002194 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002195 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002196
2197 /* restore the bssid filter and go to dummy bssid */
2198 wl1271_unjoin(wl);
2199 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200 }
2201 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002202
Arik Nemtsove78a2872010-10-16 19:07:21 +02002203 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2204 if (ret < 0)
2205 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206
Shahar Levi18357852010-10-13 16:09:41 +02002207 /*
2208 * Takes care of: New association with HT enable,
2209 * HT information change in beacon.
2210 */
2211 if (sta &&
2212 (changed & BSS_CHANGED_HT) &&
2213 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2214 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2215 if (ret < 0) {
2216 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002217 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002218 }
2219 ret = wl1271_acx_set_ht_information(wl,
2220 bss_conf->ht_operation_mode);
2221 if (ret < 0) {
2222 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002223 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002224 }
2225 }
2226 /*
2227 * Takes care of: New association without HT,
2228 * Disassociation.
2229 */
2230 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2231 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2232 if (ret < 0) {
2233 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002234 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002235 }
2236 }
2237
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002238 if (changed & BSS_CHANGED_ARP_FILTER) {
2239 __be32 addr = bss_conf->arp_addr_list[0];
2240 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2241
Eliad Pellerc5312772010-12-09 11:31:27 +02002242 if (bss_conf->arp_addr_cnt == 1 &&
2243 bss_conf->arp_filter_enabled) {
2244 /*
2245 * The template should have been configured only upon
2246 * association. however, it seems that the correct ip
2247 * isn't being set (when sending), so we have to
2248 * reconfigure the template upon every ip change.
2249 */
2250 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2251 if (ret < 0) {
2252 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002253 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002254 }
2255
2256 ret = wl1271_acx_arp_ip_filter(wl,
2257 (ACX_ARP_FILTER_ARP_FILTERING |
2258 ACX_ARP_FILTER_AUTO_ARP),
2259 addr);
2260 } else
2261 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002262
2263 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002264 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002265 }
2266
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002267 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002268 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002269 if (ret < 0) {
2270 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002271 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002272 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002273 }
2274
Arik Nemtsove78a2872010-10-16 19:07:21 +02002275out:
2276 return;
2277}
2278
2279static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2280 struct ieee80211_vif *vif,
2281 struct ieee80211_bss_conf *bss_conf,
2282 u32 changed)
2283{
2284 struct wl1271 *wl = hw->priv;
2285 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2286 int ret;
2287
2288 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2289 (int)changed);
2290
2291 mutex_lock(&wl->mutex);
2292
2293 if (unlikely(wl->state == WL1271_STATE_OFF))
2294 goto out;
2295
2296 ret = wl1271_ps_elp_wakeup(wl, false);
2297 if (ret < 0)
2298 goto out;
2299
2300 if (is_ap)
2301 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2302 else
2303 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2304
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305 wl1271_ps_elp_sleep(wl);
2306
2307out:
2308 mutex_unlock(&wl->mutex);
2309}
2310
Kalle Valoc6999d82010-02-18 13:25:41 +02002311static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2312 const struct ieee80211_tx_queue_params *params)
2313{
2314 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002315 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02002316 int ret;
2317
2318 mutex_lock(&wl->mutex);
2319
2320 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2321
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002322 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2323 ret = -EAGAIN;
2324 goto out;
2325 }
2326
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002327 ret = wl1271_ps_elp_wakeup(wl, false);
2328 if (ret < 0)
2329 goto out;
2330
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002331 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02002332 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2333 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02002334 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02002335 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002336 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02002337
Kalle Valo4695dc92010-03-18 12:26:38 +02002338 if (params->uapsd)
2339 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2340 else
2341 ps_scheme = CONF_PS_SCHEME_LEGACY;
2342
Kalle Valoc6999d82010-02-18 13:25:41 +02002343 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2344 CONF_CHANNEL_TYPE_EDCF,
2345 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02002346 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02002347 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002348 goto out_sleep;
2349
2350out_sleep:
2351 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002352
2353out:
2354 mutex_unlock(&wl->mutex);
2355
2356 return ret;
2357}
2358
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002359static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2360{
2361
2362 struct wl1271 *wl = hw->priv;
2363 u64 mactime = ULLONG_MAX;
2364 int ret;
2365
2366 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2367
2368 mutex_lock(&wl->mutex);
2369
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002370 if (unlikely(wl->state == WL1271_STATE_OFF))
2371 goto out;
2372
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002373 ret = wl1271_ps_elp_wakeup(wl, false);
2374 if (ret < 0)
2375 goto out;
2376
2377 ret = wl1271_acx_tsf_info(wl, &mactime);
2378 if (ret < 0)
2379 goto out_sleep;
2380
2381out_sleep:
2382 wl1271_ps_elp_sleep(wl);
2383
2384out:
2385 mutex_unlock(&wl->mutex);
2386 return mactime;
2387}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388
John W. Linvilleece550d2010-07-28 16:41:06 -04002389static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2390 struct survey_info *survey)
2391{
2392 struct wl1271 *wl = hw->priv;
2393 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002394
John W. Linvilleece550d2010-07-28 16:41:06 -04002395 if (idx != 0)
2396 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002397
John W. Linvilleece550d2010-07-28 16:41:06 -04002398 survey->channel = conf->channel;
2399 survey->filled = SURVEY_INFO_NOISE_DBM;
2400 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002401
John W. Linvilleece550d2010-07-28 16:41:06 -04002402 return 0;
2403}
2404
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002405static int wl1271_allocate_hlid(struct wl1271 *wl,
2406 struct ieee80211_sta *sta,
2407 u8 *hlid)
2408{
2409 struct wl1271_station *wl_sta;
2410 int id;
2411
2412 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2413 if (id >= AP_MAX_STATIONS) {
2414 wl1271_warning("could not allocate HLID - too much stations");
2415 return -EBUSY;
2416 }
2417
2418 wl_sta = (struct wl1271_station *)sta->drv_priv;
2419
2420 __set_bit(id, wl->ap_hlid_map);
2421 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2422 *hlid = wl_sta->hlid;
2423 return 0;
2424}
2425
2426static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2427{
2428 int id = hlid - WL1271_AP_STA_HLID_START;
2429
2430 __clear_bit(id, wl->ap_hlid_map);
2431}
2432
2433static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2434 struct ieee80211_vif *vif,
2435 struct ieee80211_sta *sta)
2436{
2437 struct wl1271 *wl = hw->priv;
2438 int ret = 0;
2439 u8 hlid;
2440
2441 mutex_lock(&wl->mutex);
2442
2443 if (unlikely(wl->state == WL1271_STATE_OFF))
2444 goto out;
2445
2446 if (wl->bss_type != BSS_TYPE_AP_BSS)
2447 goto out;
2448
2449 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2450
2451 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2452 if (ret < 0)
2453 goto out;
2454
2455 ret = wl1271_ps_elp_wakeup(wl, false);
2456 if (ret < 0)
2457 goto out;
2458
2459 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2460 if (ret < 0)
2461 goto out_sleep;
2462
2463out_sleep:
2464 wl1271_ps_elp_sleep(wl);
2465
2466out:
2467 mutex_unlock(&wl->mutex);
2468 return ret;
2469}
2470
2471static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2472 struct ieee80211_vif *vif,
2473 struct ieee80211_sta *sta)
2474{
2475 struct wl1271 *wl = hw->priv;
2476 struct wl1271_station *wl_sta;
2477 int ret = 0, id;
2478
2479 mutex_lock(&wl->mutex);
2480
2481 if (unlikely(wl->state == WL1271_STATE_OFF))
2482 goto out;
2483
2484 if (wl->bss_type != BSS_TYPE_AP_BSS)
2485 goto out;
2486
2487 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2488
2489 wl_sta = (struct wl1271_station *)sta->drv_priv;
2490 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2491 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2492 goto out;
2493
2494 ret = wl1271_ps_elp_wakeup(wl, false);
2495 if (ret < 0)
2496 goto out;
2497
2498 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2499 if (ret < 0)
2500 goto out_sleep;
2501
2502 wl1271_free_hlid(wl, wl_sta->hlid);
2503
2504out_sleep:
2505 wl1271_ps_elp_sleep(wl);
2506
2507out:
2508 mutex_unlock(&wl->mutex);
2509 return ret;
2510}
2511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512/* can't be const, mac80211 writes to this */
2513static struct ieee80211_rate wl1271_rates[] = {
2514 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002515 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2516 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002518 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2519 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2521 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002522 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2523 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2525 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002526 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2527 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2529 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002530 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2531 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002532 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002533 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2534 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002536 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2537 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002539 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2540 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002542 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2543 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002545 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2546 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002547 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002548 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2549 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002551 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2552 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553};
2554
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002555/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002557 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002558 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002559 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2560 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2561 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002562 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002563 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2564 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2565 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002566 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002567 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2568 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2569 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570};
2571
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002572/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002573static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002574 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002575 7, /* CONF_HW_RXTX_RATE_MCS7 */
2576 6, /* CONF_HW_RXTX_RATE_MCS6 */
2577 5, /* CONF_HW_RXTX_RATE_MCS5 */
2578 4, /* CONF_HW_RXTX_RATE_MCS4 */
2579 3, /* CONF_HW_RXTX_RATE_MCS3 */
2580 2, /* CONF_HW_RXTX_RATE_MCS2 */
2581 1, /* CONF_HW_RXTX_RATE_MCS1 */
2582 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002583
2584 11, /* CONF_HW_RXTX_RATE_54 */
2585 10, /* CONF_HW_RXTX_RATE_48 */
2586 9, /* CONF_HW_RXTX_RATE_36 */
2587 8, /* CONF_HW_RXTX_RATE_24 */
2588
2589 /* TI-specific rate */
2590 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2591
2592 7, /* CONF_HW_RXTX_RATE_18 */
2593 6, /* CONF_HW_RXTX_RATE_12 */
2594 3, /* CONF_HW_RXTX_RATE_11 */
2595 5, /* CONF_HW_RXTX_RATE_9 */
2596 4, /* CONF_HW_RXTX_RATE_6 */
2597 2, /* CONF_HW_RXTX_RATE_5_5 */
2598 1, /* CONF_HW_RXTX_RATE_2 */
2599 0 /* CONF_HW_RXTX_RATE_1 */
2600};
2601
Shahar Levie8b03a22010-10-13 16:09:39 +02002602/* 11n STA capabilities */
2603#define HW_RX_HIGHEST_RATE 72
2604
Shahar Levi00d20102010-11-08 11:20:10 +00002605#ifdef CONFIG_WL12XX_HT
2606#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002607 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2608 .ht_supported = true, \
2609 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2610 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2611 .mcs = { \
2612 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2613 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2614 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2615 }, \
2616}
Shahar Levi18357852010-10-13 16:09:41 +02002617#else
Shahar Levi00d20102010-11-08 11:20:10 +00002618#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002619 .ht_supported = false, \
2620}
2621#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623/* can't be const, mac80211 writes to this */
2624static struct ieee80211_supported_band wl1271_band_2ghz = {
2625 .channels = wl1271_channels,
2626 .n_channels = ARRAY_SIZE(wl1271_channels),
2627 .bitrates = wl1271_rates,
2628 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002629 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630};
2631
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002632/* 5 GHz data rates for WL1273 */
2633static struct ieee80211_rate wl1271_rates_5ghz[] = {
2634 { .bitrate = 60,
2635 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2636 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2637 { .bitrate = 90,
2638 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2639 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2640 { .bitrate = 120,
2641 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2642 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2643 { .bitrate = 180,
2644 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2645 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2646 { .bitrate = 240,
2647 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2648 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2649 { .bitrate = 360,
2650 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2651 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2652 { .bitrate = 480,
2653 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2654 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2655 { .bitrate = 540,
2656 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2657 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2658};
2659
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002660/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002661static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002662 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002663 { .hw_value = 8, .center_freq = 5040},
2664 { .hw_value = 9, .center_freq = 5045},
2665 { .hw_value = 11, .center_freq = 5055},
2666 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002667 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002668 { .hw_value = 34, .center_freq = 5170},
2669 { .hw_value = 36, .center_freq = 5180},
2670 { .hw_value = 38, .center_freq = 5190},
2671 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002672 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002673 { .hw_value = 44, .center_freq = 5220},
2674 { .hw_value = 46, .center_freq = 5230},
2675 { .hw_value = 48, .center_freq = 5240},
2676 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002677 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002678 { .hw_value = 60, .center_freq = 5300},
2679 { .hw_value = 64, .center_freq = 5320},
2680 { .hw_value = 100, .center_freq = 5500},
2681 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002682 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002683 { .hw_value = 112, .center_freq = 5560},
2684 { .hw_value = 116, .center_freq = 5580},
2685 { .hw_value = 120, .center_freq = 5600},
2686 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002687 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002688 { .hw_value = 132, .center_freq = 5660},
2689 { .hw_value = 136, .center_freq = 5680},
2690 { .hw_value = 140, .center_freq = 5700},
2691 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002692 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002693 { .hw_value = 157, .center_freq = 5785},
2694 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002695 { .hw_value = 165, .center_freq = 5825},
2696};
2697
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002698/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002699static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002700 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002701 7, /* CONF_HW_RXTX_RATE_MCS7 */
2702 6, /* CONF_HW_RXTX_RATE_MCS6 */
2703 5, /* CONF_HW_RXTX_RATE_MCS5 */
2704 4, /* CONF_HW_RXTX_RATE_MCS4 */
2705 3, /* CONF_HW_RXTX_RATE_MCS3 */
2706 2, /* CONF_HW_RXTX_RATE_MCS2 */
2707 1, /* CONF_HW_RXTX_RATE_MCS1 */
2708 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002709
2710 7, /* CONF_HW_RXTX_RATE_54 */
2711 6, /* CONF_HW_RXTX_RATE_48 */
2712 5, /* CONF_HW_RXTX_RATE_36 */
2713 4, /* CONF_HW_RXTX_RATE_24 */
2714
2715 /* TI-specific rate */
2716 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2717
2718 3, /* CONF_HW_RXTX_RATE_18 */
2719 2, /* CONF_HW_RXTX_RATE_12 */
2720 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2721 1, /* CONF_HW_RXTX_RATE_9 */
2722 0, /* CONF_HW_RXTX_RATE_6 */
2723 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2724 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2725 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2726};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002727
2728static struct ieee80211_supported_band wl1271_band_5ghz = {
2729 .channels = wl1271_channels_5ghz,
2730 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2731 .bitrates = wl1271_rates_5ghz,
2732 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002733 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002734};
2735
Tobias Klausera0ea9492010-05-20 10:38:11 +02002736static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002737 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2738 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2739};
2740
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002741static const struct ieee80211_ops wl1271_ops = {
2742 .start = wl1271_op_start,
2743 .stop = wl1271_op_stop,
2744 .add_interface = wl1271_op_add_interface,
2745 .remove_interface = wl1271_op_remove_interface,
2746 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002747 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002748 .configure_filter = wl1271_op_configure_filter,
2749 .tx = wl1271_op_tx,
2750 .set_key = wl1271_op_set_key,
2751 .hw_scan = wl1271_op_hw_scan,
2752 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002753 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002754 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002755 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002756 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002757 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002758 .sta_add = wl1271_op_sta_add,
2759 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002760 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761};
2762
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002763
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002764u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002765{
2766 u8 idx;
2767
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002768 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002769
2770 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2771 wl1271_error("Illegal RX rate from HW: %d", rate);
2772 return 0;
2773 }
2774
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002775 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002776 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2777 wl1271_error("Unsupported RX rate from HW: %d", rate);
2778 return 0;
2779 }
2780
2781 return idx;
2782}
2783
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002784static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2785 struct device_attribute *attr,
2786 char *buf)
2787{
2788 struct wl1271 *wl = dev_get_drvdata(dev);
2789 ssize_t len;
2790
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002791 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002792
2793 mutex_lock(&wl->mutex);
2794 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2795 wl->sg_enabled);
2796 mutex_unlock(&wl->mutex);
2797
2798 return len;
2799
2800}
2801
2802static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2803 struct device_attribute *attr,
2804 const char *buf, size_t count)
2805{
2806 struct wl1271 *wl = dev_get_drvdata(dev);
2807 unsigned long res;
2808 int ret;
2809
2810 ret = strict_strtoul(buf, 10, &res);
2811
2812 if (ret < 0) {
2813 wl1271_warning("incorrect value written to bt_coex_mode");
2814 return count;
2815 }
2816
2817 mutex_lock(&wl->mutex);
2818
2819 res = !!res;
2820
2821 if (res == wl->sg_enabled)
2822 goto out;
2823
2824 wl->sg_enabled = res;
2825
2826 if (wl->state == WL1271_STATE_OFF)
2827 goto out;
2828
2829 ret = wl1271_ps_elp_wakeup(wl, false);
2830 if (ret < 0)
2831 goto out;
2832
2833 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2834 wl1271_ps_elp_sleep(wl);
2835
2836 out:
2837 mutex_unlock(&wl->mutex);
2838 return count;
2839}
2840
2841static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2842 wl1271_sysfs_show_bt_coex_state,
2843 wl1271_sysfs_store_bt_coex_state);
2844
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002845static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2846 struct device_attribute *attr,
2847 char *buf)
2848{
2849 struct wl1271 *wl = dev_get_drvdata(dev);
2850 ssize_t len;
2851
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002852 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002853
2854 mutex_lock(&wl->mutex);
2855 if (wl->hw_pg_ver >= 0)
2856 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2857 else
2858 len = snprintf(buf, len, "n/a\n");
2859 mutex_unlock(&wl->mutex);
2860
2861 return len;
2862}
2863
2864static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2865 wl1271_sysfs_show_hw_pg_ver, NULL);
2866
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002867int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002868{
2869 int ret;
2870
2871 if (wl->mac80211_registered)
2872 return 0;
2873
2874 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2875
2876 ret = ieee80211_register_hw(wl->hw);
2877 if (ret < 0) {
2878 wl1271_error("unable to register mac80211 hw: %d", ret);
2879 return ret;
2880 }
2881
2882 wl->mac80211_registered = true;
2883
Eliad Pellerd60080a2010-11-24 12:53:16 +02002884 wl1271_debugfs_init(wl);
2885
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002886 register_netdevice_notifier(&wl1271_dev_notifier);
2887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002888 wl1271_notice("loaded");
2889
2890 return 0;
2891}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002892EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002893
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002894void wl1271_unregister_hw(struct wl1271 *wl)
2895{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002896 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002897 ieee80211_unregister_hw(wl->hw);
2898 wl->mac80211_registered = false;
2899
2900}
2901EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2902
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002903int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002905 static const u32 cipher_suites[] = {
2906 WLAN_CIPHER_SUITE_WEP40,
2907 WLAN_CIPHER_SUITE_WEP104,
2908 WLAN_CIPHER_SUITE_TKIP,
2909 WLAN_CIPHER_SUITE_CCMP,
2910 WL1271_CIPHER_SUITE_GEM,
2911 };
2912
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002913 /* The tx descriptor buffer and the TKIP space. */
2914 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2915 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916
2917 /* unit us */
2918 /* FIXME: find a proper value */
2919 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002920 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921
2922 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002923 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002924 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002925 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002926 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002927 IEEE80211_HW_CONNECTION_MONITOR |
2928 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002930 wl->hw->wiphy->cipher_suites = cipher_suites;
2931 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2932
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002933 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2934 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002935 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02002936 /*
2937 * Maximum length of elements in scanning probe request templates
2938 * should be the maximum length possible for a template, without
2939 * the IEEE80211 header of the template
2940 */
2941 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
2942 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002944 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002945
Kalle Valo12bd8942010-03-18 12:26:33 +02002946 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002947 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002948
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002949 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2950
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002951 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002953 wl->hw->sta_data_size = sizeof(struct wl1271_station);
2954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 return 0;
2956}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002957EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002960
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002961struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002962{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002964 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002966 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002967 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968
2969 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2970 if (!hw) {
2971 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002972 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002973 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002974 }
2975
Julia Lawall929ebd32010-05-15 23:16:39 +02002976 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002977 if (!plat_dev) {
2978 wl1271_error("could not allocate platform_device");
2979 ret = -ENOMEM;
2980 goto err_plat_alloc;
2981 }
2982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 wl = hw->priv;
2984 memset(wl, 0, sizeof(*wl));
2985
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002986 INIT_LIST_HEAD(&wl->list);
2987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002989 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990
Juuso Oikarinen6742f552010-12-13 09:52:37 +02002991 for (i = 0; i < NUM_TX_QUEUES; i++)
2992 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002994 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002995 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02002996 INIT_WORK(&wl->irq_work, wl1271_irq_work);
2997 INIT_WORK(&wl->tx_work, wl1271_tx_work);
2998 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
2999 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003001 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003004 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3005 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003006 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003008 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003009 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003010 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3011 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003012 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003013 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003014 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003015 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003016 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003018 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003019 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003020 wl->tx_frames[i] = NULL;
3021
3022 spin_lock_init(&wl->wl_lock);
3023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003024 wl->state = WL1271_STATE_OFF;
3025 mutex_init(&wl->mutex);
3026
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003027 /* Apply default driver configuration. */
3028 wl1271_conf_init(wl);
3029
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003030 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3031 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3032 if (!wl->aggr_buf) {
3033 ret = -ENOMEM;
3034 goto err_hw;
3035 }
3036
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003037 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003038 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003039 if (ret) {
3040 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003041 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003042 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003043 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003044
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003045 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003046 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003047 if (ret < 0) {
3048 wl1271_error("failed to create sysfs file bt_coex_state");
3049 goto err_platform;
3050 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003051
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003052 /* Create sysfs file to get HW PG version */
3053 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3054 if (ret < 0) {
3055 wl1271_error("failed to create sysfs file hw_pg_ver");
3056 goto err_bt_coex_state;
3057 }
3058
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003059 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003060
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003061err_bt_coex_state:
3062 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3063
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003064err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003065 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003066
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003067err_aggr:
3068 free_pages((unsigned long)wl->aggr_buf, order);
3069
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003070err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003071 wl1271_debugfs_exit(wl);
3072 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003073
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003074err_plat_alloc:
3075 ieee80211_free_hw(hw);
3076
3077err_hw_alloc:
3078
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003079 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003080}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003081EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003082
3083int wl1271_free_hw(struct wl1271 *wl)
3084{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003085 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003086 free_pages((unsigned long)wl->aggr_buf,
3087 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003088 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003089
3090 wl1271_debugfs_exit(wl);
3091
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003092 vfree(wl->fw);
3093 wl->fw = NULL;
3094 kfree(wl->nvs);
3095 wl->nvs = NULL;
3096
3097 kfree(wl->fw_status);
3098 kfree(wl->tx_res_if);
3099
3100 ieee80211_free_hw(wl->hw);
3101
3102 return 0;
3103}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003104EXPORT_SYMBOL_GPL(wl1271_free_hw);
3105
Eliad Peller17c17552010-12-12 12:15:35 +02003106u32 wl12xx_debug_level;
3107EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3108module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3109MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3110
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003111MODULE_LICENSE("GPL");
3112MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3113MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");