blob: 8b897e337fbb1fda60fe6e2997ca71a9e978d331 [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] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200946 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
947 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200948 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
949 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
950 }
Shahar Levi18357852010-10-13 16:09:41 +0200951
Shahar Levi00d20102010-11-08 11:20:10 +0000952#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200953 if (sta &&
954 sta->ht_cap.ht_supported &&
955 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
956 sta->ht_cap.mcs.rx_mask[0])) {
957 /* Clean MCS bits before setting them */
958 wl->sta_rate_set &= HW_BG_RATES_MASK;
959 wl->sta_rate_set |=
960 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
961 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
962 }
963#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200964 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200965 spin_unlock_irqrestore(&wl->wl_lock, flags);
966
967 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200968 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
969 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970
971 /*
972 * The chip specific setup must run before the first TX packet -
973 * before that, the tx_work will not be initialized!
974 */
975
Ido Yariva5225502010-10-12 14:49:10 +0200976 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
977 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978
979 /*
980 * The workqueue is slow to process the tx_queue and we need stop
981 * the queue here, otherwise the queue will get too long.
982 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200983 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200984 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200986 spin_lock_irqsave(&wl->wl_lock, flags);
987 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200988 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200989 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 }
991
992 return NETDEV_TX_OK;
993}
994
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300995static struct notifier_block wl1271_dev_notifier = {
996 .notifier_call = wl1271_dev_notify,
997};
998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999static int wl1271_op_start(struct ieee80211_hw *hw)
1000{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001001 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1002
1003 /*
1004 * We have to delay the booting of the hardware because
1005 * we need to know the local MAC address before downloading and
1006 * initializing the firmware. The MAC address cannot be changed
1007 * after boot, and without the proper MAC address, the firmware
1008 * will not function properly.
1009 *
1010 * The MAC address is first known when the corresponding interface
1011 * is added. That is where we will initialize the hardware.
1012 */
1013
1014 return 0;
1015}
1016
1017static void wl1271_op_stop(struct ieee80211_hw *hw)
1018{
1019 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1020}
1021
1022static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1023 struct ieee80211_vif *vif)
1024{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001026 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001027 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001029 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001031 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1032 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
1034 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001035 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001036 wl1271_debug(DEBUG_MAC80211,
1037 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001038 ret = -EBUSY;
1039 goto out;
1040 }
1041
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001042 switch (vif->type) {
1043 case NL80211_IFTYPE_STATION:
1044 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001045 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001046 break;
1047 case NL80211_IFTYPE_ADHOC:
1048 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001049 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001050 break;
1051 default:
1052 ret = -EOPNOTSUPP;
1053 goto out;
1054 }
1055
1056 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
1058 if (wl->state != WL1271_STATE_OFF) {
1059 wl1271_error("cannot start because not in off state: %d",
1060 wl->state);
1061 ret = -EBUSY;
1062 goto out;
1063 }
1064
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001065 while (retries) {
1066 retries--;
1067 ret = wl1271_chip_wakeup(wl);
1068 if (ret < 0)
1069 goto power_off;
1070
1071 ret = wl1271_boot(wl);
1072 if (ret < 0)
1073 goto power_off;
1074
1075 ret = wl1271_hw_init(wl);
1076 if (ret < 0)
1077 goto irq_disable;
1078
Eliad Peller71125ab2010-10-28 21:46:43 +02001079 booted = true;
1080 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001082irq_disable:
1083 wl1271_disable_interrupts(wl);
1084 mutex_unlock(&wl->mutex);
1085 /* Unlocking the mutex in the middle of handling is
1086 inherently unsafe. In this case we deem it safe to do,
1087 because we need to let any possibly pending IRQ out of
1088 the system (and while we are WL1271_STATE_OFF the IRQ
1089 work function will not do anything.) Also, any other
1090 possible concurrent operations will fail due to the
1091 current state, hence the wl1271 struct should be safe. */
1092 cancel_work_sync(&wl->irq_work);
1093 mutex_lock(&wl->mutex);
1094power_off:
1095 wl1271_power_off(wl);
1096 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097
Eliad Peller71125ab2010-10-28 21:46:43 +02001098 if (!booted) {
1099 wl1271_error("firmware boot failed despite %d retries",
1100 WL1271_BOOT_RETRIES);
1101 goto out;
1102 }
1103
1104 wl->vif = vif;
1105 wl->state = WL1271_STATE_ON;
1106 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1107
1108 /* update hw/fw version info in wiphy struct */
1109 wiphy->hw_version = wl->chip.id;
1110 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1111 sizeof(wiphy->fw_version));
1112
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001113 /*
1114 * Now we know if 11a is supported (info from the NVS), so disable
1115 * 11a channels if not supported
1116 */
1117 if (!wl->enable_11a)
1118 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1119
1120 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1121 wl->enable_11a ? "" : "not ");
1122
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001123out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124 mutex_unlock(&wl->mutex);
1125
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001126 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001127 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001128
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129 return ret;
1130}
1131
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001132static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134 int i;
1135
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001136 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001138 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001140 list_del(&wl->list);
1141
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001142 WARN_ON(wl->state != WL1271_STATE_ON);
1143
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001144 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001145 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001146 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001147
Luciano Coelho08688d62010-07-08 17:50:07 +03001148 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001149 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1150 kfree(wl->scan.scanned_ch);
1151 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001152 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001153 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 }
1155
1156 wl->state = WL1271_STATE_OFF;
1157
1158 wl1271_disable_interrupts(wl);
1159
1160 mutex_unlock(&wl->mutex);
1161
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001162 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163 cancel_work_sync(&wl->irq_work);
1164 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001165 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001166 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167
1168 mutex_lock(&wl->mutex);
1169
1170 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001171 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172 wl1271_power_off(wl);
1173
1174 memset(wl->bssid, 0, ETH_ALEN);
1175 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1176 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001177 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001178 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001179 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001180
1181 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001182 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1184 wl->tx_blocks_available = 0;
1185 wl->tx_results_count = 0;
1186 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001187 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001188 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 wl->time_offset = 0;
1190 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001191 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1192 wl->sta_rate_set = 0;
1193 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001194 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001195 wl->filters = 0;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001196 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 for (i = 0; i < NUM_TX_QUEUES; i++)
1199 wl->tx_blocks_freed[i] = 0;
1200
1201 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001202
1203 kfree(wl->fw_status);
1204 wl->fw_status = NULL;
1205 kfree(wl->tx_res_if);
1206 wl->tx_res_if = NULL;
1207 kfree(wl->target_mem_map);
1208 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001209}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001210
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001211static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1212 struct ieee80211_vif *vif)
1213{
1214 struct wl1271 *wl = hw->priv;
1215
1216 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001217 /*
1218 * wl->vif can be null here if someone shuts down the interface
1219 * just when hardware recovery has been started.
1220 */
1221 if (wl->vif) {
1222 WARN_ON(wl->vif != vif);
1223 __wl1271_op_remove_interface(wl);
1224 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001225
Juuso Oikarinen67353292010-11-18 15:19:02 +02001226 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001227 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228}
1229
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001230static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1231{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001232 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001233
1234 /* combine requested filters with current filter config */
1235 filters = wl->filters | filters;
1236
1237 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1238
1239 if (filters & FIF_PROMISC_IN_BSS) {
1240 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1241 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1242 wl->rx_config |= CFG_BSSID_FILTER_EN;
1243 }
1244 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1245 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1246 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1247 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1248 }
1249 if (filters & FIF_OTHER_BSS) {
1250 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1251 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1252 }
1253 if (filters & FIF_CONTROL) {
1254 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1255 wl->rx_filter |= CFG_RX_CTL_EN;
1256 }
1257 if (filters & FIF_FCSFAIL) {
1258 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1259 wl->rx_filter |= CFG_RX_FCS_ERROR;
1260 }
1261}
1262
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001263static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001264{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001265 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001266 /* we need to use a dummy BSSID for now */
1267 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1268 0xad, 0xbe, 0xef };
1269
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001270 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1271
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001272 /* pass through frames from all BSS */
1273 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1274
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001275 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001276 if (ret < 0)
1277 goto out;
1278
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001279 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001280
1281out:
1282 return ret;
1283}
1284
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001285static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001286{
1287 int ret;
1288
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001289 /*
1290 * One of the side effects of the JOIN command is that is clears
1291 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1292 * to a WPA/WPA2 access point will therefore kill the data-path.
1293 * Currently there is no supported scenario for JOIN during
1294 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1295 * must be handled somehow.
1296 *
1297 */
1298 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1299 wl1271_info("JOIN while associated.");
1300
1301 if (set_assoc)
1302 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1303
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001304 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1305 if (ret < 0)
1306 goto out;
1307
1308 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1309
1310 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1311 goto out;
1312
1313 /*
1314 * The join command disable the keep-alive mode, shut down its process,
1315 * and also clear the template config, so we need to reset it all after
1316 * the join. The acx_aid starts the keep-alive process, and the order
1317 * of the commands below is relevant.
1318 */
1319 ret = wl1271_acx_keep_alive_mode(wl, true);
1320 if (ret < 0)
1321 goto out;
1322
1323 ret = wl1271_acx_aid(wl, wl->aid);
1324 if (ret < 0)
1325 goto out;
1326
1327 ret = wl1271_cmd_build_klv_null_data(wl);
1328 if (ret < 0)
1329 goto out;
1330
1331 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1332 ACX_KEEP_ALIVE_TPL_VALID);
1333 if (ret < 0)
1334 goto out;
1335
1336out:
1337 return ret;
1338}
1339
1340static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001341{
1342 int ret;
1343
1344 /* to stop listening to a channel, we disconnect */
1345 ret = wl1271_cmd_disconnect(wl);
1346 if (ret < 0)
1347 goto out;
1348
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001349 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001350 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001351
1352 /* stop filterting packets based on bssid */
1353 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001354
1355out:
1356 return ret;
1357}
1358
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001359static void wl1271_set_band_rate(struct wl1271 *wl)
1360{
1361 if (wl->band == IEEE80211_BAND_2GHZ)
1362 wl->basic_rate_set = wl->conf.tx.basic_rate;
1363 else
1364 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1365}
1366
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001367static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001368{
1369 int ret;
1370
1371 if (idle) {
1372 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1373 ret = wl1271_unjoin(wl);
1374 if (ret < 0)
1375 goto out;
1376 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001377 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001378 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001379 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001380 if (ret < 0)
1381 goto out;
1382 ret = wl1271_acx_keep_alive_config(
1383 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1384 ACX_KEEP_ALIVE_TPL_INVALID);
1385 if (ret < 0)
1386 goto out;
1387 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1388 } else {
1389 /* increment the session counter */
1390 wl->session_counter++;
1391 if (wl->session_counter >= SESSION_COUNTER_MAX)
1392 wl->session_counter = 0;
1393 ret = wl1271_dummy_join(wl);
1394 if (ret < 0)
1395 goto out;
1396 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1397 }
1398
1399out:
1400 return ret;
1401}
1402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1404{
1405 struct wl1271 *wl = hw->priv;
1406 struct ieee80211_conf *conf = &hw->conf;
1407 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001408 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409
1410 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1411
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001412 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1413 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 channel,
1415 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001416 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001417 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1418 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001420 /*
1421 * mac80211 will go to idle nearly immediately after transmitting some
1422 * frames, such as the deauth. To make sure those frames reach the air,
1423 * wait here until the TX queue is fully flushed.
1424 */
1425 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1426 (conf->flags & IEEE80211_CONF_IDLE))
1427 wl1271_tx_flush(wl);
1428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 mutex_lock(&wl->mutex);
1430
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001431 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1432 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001433 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001434 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001435
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001436 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438 ret = wl1271_ps_elp_wakeup(wl, false);
1439 if (ret < 0)
1440 goto out;
1441
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001442 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001443 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1444 ((wl->band != conf->channel->band) ||
1445 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001446 wl->band = conf->channel->band;
1447 wl->channel = channel;
1448
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001449 if (!is_ap) {
1450 /*
1451 * FIXME: the mac80211 should really provide a fixed
1452 * rate to use here. for now, just use the smallest
1453 * possible rate for the band as a fixed rate for
1454 * association frames and other control messages.
1455 */
1456 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1457 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001458
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001459 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1460 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001461 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001462 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001463 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001464
1465 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1466 ret = wl1271_join(wl, false);
1467 if (ret < 0)
1468 wl1271_warning("cmd join on channel "
1469 "failed %d", ret);
1470 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001471 }
1472 }
1473
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001474 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1475 ret = wl1271_sta_handle_idle(wl,
1476 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001477 if (ret < 0)
1478 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 }
1480
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001481 /*
1482 * if mac80211 changes the PSM mode, make sure the mode is not
1483 * incorrectly changed after the pspoll failure active window.
1484 */
1485 if (changed & IEEE80211_CONF_CHANGE_PS)
1486 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1487
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001488 if (conf->flags & IEEE80211_CONF_PS &&
1489 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1490 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
1492 /*
1493 * We enter PSM only if we're already associated.
1494 * If we're not, we'll enter it when joining an SSID,
1495 * through the bss_info_changed() hook.
1496 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001497 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001498 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001499 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001500 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001503 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001504 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001506 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001508 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001509 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001510 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 }
1512
1513 if (conf->power_level != wl->power_level) {
1514 ret = wl1271_acx_tx_power(wl, conf->power_level);
1515 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001516 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
1518 wl->power_level = conf->power_level;
1519 }
1520
1521out_sleep:
1522 wl1271_ps_elp_sleep(wl);
1523
1524out:
1525 mutex_unlock(&wl->mutex);
1526
1527 return ret;
1528}
1529
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001530struct wl1271_filter_params {
1531 bool enabled;
1532 int mc_list_length;
1533 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1534};
1535
Jiri Pirko22bedad32010-04-01 21:22:57 +00001536static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1537 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001538{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001539 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001540 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001541 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001542
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001543 if (unlikely(wl->state == WL1271_STATE_OFF))
1544 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001545
Juuso Oikarinen74441132009-10-13 12:47:53 +03001546 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001547 if (!fp) {
1548 wl1271_error("Out of memory setting filters.");
1549 return 0;
1550 }
1551
1552 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001553 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001554 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1555 fp->enabled = false;
1556 } else {
1557 fp->enabled = true;
1558 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001559 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001560 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001561 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001562 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001563 }
1564
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001565 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001566}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001568#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1569 FIF_ALLMULTI | \
1570 FIF_FCSFAIL | \
1571 FIF_BCN_PRBRESP_PROMISC | \
1572 FIF_CONTROL | \
1573 FIF_OTHER_BSS)
1574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1576 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001577 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001579 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001581 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582
Arik Nemtsov7d057862010-10-16 19:25:35 +02001583 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1584 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001586 mutex_lock(&wl->mutex);
1587
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001588 *total &= WL1271_SUPPORTED_FILTERS;
1589 changed &= WL1271_SUPPORTED_FILTERS;
1590
1591 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001592 goto out;
1593
1594 ret = wl1271_ps_elp_wakeup(wl, false);
1595 if (ret < 0)
1596 goto out;
1597
Arik Nemtsov7d057862010-10-16 19:25:35 +02001598 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1599 if (*total & FIF_ALLMULTI)
1600 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1601 else if (fp)
1602 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1603 fp->mc_list,
1604 fp->mc_list_length);
1605 if (ret < 0)
1606 goto out_sleep;
1607 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001609 /* determine, whether supported filter values have changed */
1610 if (changed == 0)
1611 goto out_sleep;
1612
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001613 /* configure filters */
1614 wl->filters = *total;
1615 wl1271_configure_filters(wl, 0);
1616
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001617 /* apply configured filters */
1618 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1619 if (ret < 0)
1620 goto out_sleep;
1621
1622out_sleep:
1623 wl1271_ps_elp_sleep(wl);
1624
1625out:
1626 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001627 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628}
1629
1630static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1631 struct ieee80211_vif *vif,
1632 struct ieee80211_sta *sta,
1633 struct ieee80211_key_conf *key_conf)
1634{
1635 struct wl1271 *wl = hw->priv;
1636 const u8 *addr;
1637 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001638 u32 tx_seq_32 = 0;
1639 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001640 u8 key_type;
1641
1642 static const u8 bcast_addr[ETH_ALEN] =
1643 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1644
1645 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1646
1647 addr = sta ? sta->addr : bcast_addr;
1648
1649 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1650 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1651 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001652 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653 key_conf->keylen, key_conf->flags);
1654 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1655
1656 if (is_zero_ether_addr(addr)) {
1657 /* We dont support TX only encryption */
1658 ret = -EOPNOTSUPP;
1659 goto out;
1660 }
1661
1662 mutex_lock(&wl->mutex);
1663
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001664 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1665 ret = -EAGAIN;
1666 goto out_unlock;
1667 }
1668
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001669 ret = wl1271_ps_elp_wakeup(wl, false);
1670 if (ret < 0)
1671 goto out_unlock;
1672
Johannes Berg97359d12010-08-10 09:46:38 +02001673 switch (key_conf->cipher) {
1674 case WLAN_CIPHER_SUITE_WEP40:
1675 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 key_type = KEY_WEP;
1677
1678 key_conf->hw_key_idx = key_conf->keyidx;
1679 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001680 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001681 key_type = KEY_TKIP;
1682
1683 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001684 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1685 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001687 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 key_type = KEY_AES;
1689
1690 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001691 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1692 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001694 case WL1271_CIPHER_SUITE_GEM:
1695 key_type = KEY_GEM;
1696 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1697 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1698 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001700 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701
1702 ret = -EOPNOTSUPP;
1703 goto out_sleep;
1704 }
1705
1706 switch (cmd) {
1707 case SET_KEY:
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001708 ret = wl1271_cmd_set_sta_key(wl, KEY_ADD_OR_REPLACE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 key_conf->keyidx, key_type,
1710 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001711 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 if (ret < 0) {
1713 wl1271_error("Could not add or replace key");
1714 goto out_sleep;
1715 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001716
1717 /* the default WEP key needs to be configured at least once */
1718 if (key_type == KEY_WEP) {
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001719 ret = wl1271_cmd_set_sta_default_wep_key(wl,
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001720 wl->default_key);
1721 if (ret < 0)
1722 goto out_sleep;
1723 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724 break;
1725
1726 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001727 /* The wl1271 does not allow to remove unicast keys - they
1728 will be cleared automatically on next CMD_JOIN. Ignore the
1729 request silently, as we dont want the mac80211 to emit
1730 an error message. */
1731 if (!is_broadcast_ether_addr(addr))
1732 break;
1733
Arik Nemtsov98bdaab2010-10-16 18:08:58 +02001734 ret = wl1271_cmd_set_sta_key(wl, KEY_REMOVE,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001735 key_conf->keyidx, key_type,
1736 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001737 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001738 if (ret < 0) {
1739 wl1271_error("Could not remove key");
1740 goto out_sleep;
1741 }
1742 break;
1743
1744 default:
1745 wl1271_error("Unsupported key cmd 0x%x", cmd);
1746 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747 break;
1748 }
1749
1750out_sleep:
1751 wl1271_ps_elp_sleep(wl);
1752
1753out_unlock:
1754 mutex_unlock(&wl->mutex);
1755
1756out:
1757 return ret;
1758}
1759
1760static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001761 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762 struct cfg80211_scan_request *req)
1763{
1764 struct wl1271 *wl = hw->priv;
1765 int ret;
1766 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001767 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768
1769 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1770
1771 if (req->n_ssids) {
1772 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001773 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 }
1775
1776 mutex_lock(&wl->mutex);
1777
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001778 if (wl->state == WL1271_STATE_OFF) {
1779 /*
1780 * We cannot return -EBUSY here because cfg80211 will expect
1781 * a call to ieee80211_scan_completed if we do - in this case
1782 * there won't be any call.
1783 */
1784 ret = -EAGAIN;
1785 goto out;
1786 }
1787
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788 ret = wl1271_ps_elp_wakeup(wl, false);
1789 if (ret < 0)
1790 goto out;
1791
Luciano Coelho5924f892010-08-04 03:46:22 +03001792 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793
1794 wl1271_ps_elp_sleep(wl);
1795
1796out:
1797 mutex_unlock(&wl->mutex);
1798
1799 return ret;
1800}
1801
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001802static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1803{
1804 struct wl1271 *wl = hw->priv;
1805 int ret = 0;
1806
1807 mutex_lock(&wl->mutex);
1808
1809 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1810 ret = -EAGAIN;
1811 goto out;
1812 }
1813
1814 ret = wl1271_ps_elp_wakeup(wl, false);
1815 if (ret < 0)
1816 goto out;
1817
1818 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1819 if (ret < 0)
1820 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1821
1822 wl1271_ps_elp_sleep(wl);
1823
1824out:
1825 mutex_unlock(&wl->mutex);
1826
1827 return ret;
1828}
1829
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1831{
1832 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001833 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834
1835 mutex_lock(&wl->mutex);
1836
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001837 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1838 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001839 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001840 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 ret = wl1271_ps_elp_wakeup(wl, false);
1843 if (ret < 0)
1844 goto out;
1845
1846 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1847 if (ret < 0)
1848 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1849
1850 wl1271_ps_elp_sleep(wl);
1851
1852out:
1853 mutex_unlock(&wl->mutex);
1854
1855 return ret;
1856}
1857
Arik Nemtsove78a2872010-10-16 19:07:21 +02001858static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001859 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001860{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001861 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001862
1863 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001864 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001865 if (ptr[0] == WLAN_EID_SSID) {
1866 wl->ssid_len = ptr[1];
1867 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02001868 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001869 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001870 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001871 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02001872
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001873 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02001874 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001875}
1876
Arik Nemtsove78a2872010-10-16 19:07:21 +02001877static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
1878 struct ieee80211_bss_conf *bss_conf,
1879 u32 changed)
1880{
1881 int ret = 0;
1882
1883 if (changed & BSS_CHANGED_ERP_SLOT) {
1884 if (bss_conf->use_short_slot)
1885 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1886 else
1887 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1888 if (ret < 0) {
1889 wl1271_warning("Set slot time failed %d", ret);
1890 goto out;
1891 }
1892 }
1893
1894 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1895 if (bss_conf->use_short_preamble)
1896 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1897 else
1898 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1899 }
1900
1901 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1902 if (bss_conf->use_cts_prot)
1903 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1904 else
1905 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1906 if (ret < 0) {
1907 wl1271_warning("Set ctsprotect failed %d", ret);
1908 goto out;
1909 }
1910 }
1911
1912out:
1913 return ret;
1914}
1915
1916static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
1917 struct ieee80211_vif *vif,
1918 struct ieee80211_bss_conf *bss_conf,
1919 u32 changed)
1920{
1921 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1922 int ret = 0;
1923
1924 if ((changed & BSS_CHANGED_BEACON_INT)) {
1925 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
1926 bss_conf->beacon_int);
1927
1928 wl->beacon_int = bss_conf->beacon_int;
1929 }
1930
1931 if ((changed & BSS_CHANGED_BEACON)) {
1932 struct ieee80211_hdr *hdr;
1933 int ieoffset = offsetof(struct ieee80211_mgmt,
1934 u.beacon.variable);
1935 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
1936 u16 tmpl_id;
1937
1938 if (!beacon)
1939 goto out;
1940
1941 wl1271_debug(DEBUG_MASTER, "beacon updated");
1942
1943 ret = wl1271_ssid_set(wl, beacon, ieoffset);
1944 if (ret < 0) {
1945 dev_kfree_skb(beacon);
1946 goto out;
1947 }
1948 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
1949 CMD_TEMPL_BEACON;
1950 ret = wl1271_cmd_template_set(wl, tmpl_id,
1951 beacon->data,
1952 beacon->len, 0,
1953 wl1271_tx_min_rate_get(wl));
1954 if (ret < 0) {
1955 dev_kfree_skb(beacon);
1956 goto out;
1957 }
1958
1959 hdr = (struct ieee80211_hdr *) beacon->data;
1960 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1961 IEEE80211_STYPE_PROBE_RESP);
1962
1963 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
1964 CMD_TEMPL_PROBE_RESPONSE;
1965 ret = wl1271_cmd_template_set(wl,
1966 tmpl_id,
1967 beacon->data,
1968 beacon->len, 0,
1969 wl1271_tx_min_rate_get(wl));
1970 dev_kfree_skb(beacon);
1971 if (ret < 0)
1972 goto out;
1973 }
1974
1975out:
1976 return ret;
1977}
1978
1979/* AP mode changes */
1980static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981 struct ieee80211_vif *vif,
1982 struct ieee80211_bss_conf *bss_conf,
1983 u32 changed)
1984{
Arik Nemtsove78a2872010-10-16 19:07:21 +02001985 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986
Arik Nemtsove78a2872010-10-16 19:07:21 +02001987 if ((changed & BSS_CHANGED_BASIC_RATES)) {
1988 u32 rates = bss_conf->basic_rates;
1989 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990
Arik Nemtsove78a2872010-10-16 19:07:21 +02001991 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
1992 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1993 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
1994 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995
Arik Nemtsove78a2872010-10-16 19:07:21 +02001996 /* update the AP management rate policy with the new rates */
1997 mgmt_rc.enabled_rates = wl->basic_rate_set;
1998 mgmt_rc.long_retry_limit = 10;
1999 mgmt_rc.short_retry_limit = 10;
2000 mgmt_rc.aflags = 0;
2001 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2002 ACX_TX_AP_MODE_MGMT_RATE);
2003 if (ret < 0) {
2004 wl1271_error("AP mgmt policy change failed %d", ret);
2005 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002006 }
2007 }
2008
Arik Nemtsove78a2872010-10-16 19:07:21 +02002009 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2010 if (ret < 0)
2011 goto out;
2012
2013 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2014 if (bss_conf->enable_beacon) {
2015 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2016 ret = wl1271_cmd_start_bss(wl);
2017 if (ret < 0)
2018 goto out;
2019
2020 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2021 wl1271_debug(DEBUG_AP, "started AP");
2022 }
2023 } else {
2024 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2025 ret = wl1271_cmd_stop_bss(wl);
2026 if (ret < 0)
2027 goto out;
2028
2029 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2030 wl1271_debug(DEBUG_AP, "stopped AP");
2031 }
2032 }
2033 }
2034
2035 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2036 if (ret < 0)
2037 goto out;
2038out:
2039 return;
2040}
2041
2042/* STA/IBSS mode changes */
2043static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2044 struct ieee80211_vif *vif,
2045 struct ieee80211_bss_conf *bss_conf,
2046 u32 changed)
2047{
2048 bool do_join = false, set_assoc = false;
2049 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2050 int ret;
2051 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2052
2053 if (is_ibss) {
2054 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2055 changed);
2056 if (ret < 0)
2057 goto out;
2058 }
2059
2060 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2061 do_join = true;
2062
2063 /* Need to update the SSID (for filtering etc) */
2064 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2065 do_join = true;
2066
2067 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002068 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2069 bss_conf->enable_beacon ? "enabled" : "disabled");
2070
2071 if (bss_conf->enable_beacon)
2072 wl->set_bss_type = BSS_TYPE_IBSS;
2073 else
2074 wl->set_bss_type = BSS_TYPE_STA_BSS;
2075 do_join = true;
2076 }
2077
Arik Nemtsove78a2872010-10-16 19:07:21 +02002078 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002079 bool enable = false;
2080 if (bss_conf->cqm_rssi_thold)
2081 enable = true;
2082 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2083 bss_conf->cqm_rssi_thold,
2084 bss_conf->cqm_rssi_hyst);
2085 if (ret < 0)
2086 goto out;
2087 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2088 }
2089
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002090 if ((changed & BSS_CHANGED_BSSID) &&
2091 /*
2092 * Now we know the correct bssid, so we send a new join command
2093 * and enable the BSSID filter
2094 */
2095 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002096 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002097
Arik Nemtsove78a2872010-10-16 19:07:21 +02002098 ret = wl1271_cmd_build_null_data(wl);
2099 if (ret < 0)
2100 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002101
Arik Nemtsove78a2872010-10-16 19:07:21 +02002102 ret = wl1271_build_qos_null_data(wl);
2103 if (ret < 0)
2104 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002105
Arik Nemtsove78a2872010-10-16 19:07:21 +02002106 /* filter out all packets not from this BSSID */
2107 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002108
Arik Nemtsove78a2872010-10-16 19:07:21 +02002109 /* Need to update the BSSID (for filtering etc) */
2110 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002111 }
2112
Arik Nemtsove78a2872010-10-16 19:07:21 +02002113 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002115 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002116 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002118 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002120 wl->ps_poll_failures = 0;
2121
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002122 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002123 * use basic rates from AP, and determine lowest rate
2124 * to use with control frames.
2125 */
2126 rates = bss_conf->basic_rates;
2127 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2128 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002129 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002130 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002131 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002132 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002133
2134 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002135 * with wl1271, we don't need to update the
2136 * beacon_int and dtim_period, because the firmware
2137 * updates it by itself when the first beacon is
2138 * received after a join.
2139 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2141 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002142 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002144 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002145 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002146 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002147 dev_kfree_skb(wl->probereq);
2148 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2149 ieoffset = offsetof(struct ieee80211_mgmt,
2150 u.probe_req.variable);
2151 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002152
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002153 /* enable the connection monitoring feature */
2154 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002156 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157
2158 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002159 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2160 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002161 enum wl1271_cmd_ps_mode mode;
2162
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002164 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002165 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002166 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002168 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002170 } else {
2171 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002172 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002173 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002174 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002175
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002176 /* free probe-request template */
2177 dev_kfree_skb(wl->probereq);
2178 wl->probereq = NULL;
2179
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002180 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002181 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002182
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002183 /* revert back to minimum rates for the current band */
2184 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002185 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002186 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002187 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002188 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002189
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002190 /* disable connection monitor features */
2191 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002192
2193 /* Disable the keep-alive feature */
2194 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002195 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002196 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002197
2198 /* restore the bssid filter and go to dummy bssid */
2199 wl1271_unjoin(wl);
2200 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 }
2202 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002203
Arik Nemtsove78a2872010-10-16 19:07:21 +02002204 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2205 if (ret < 0)
2206 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207
Shahar Levi18357852010-10-13 16:09:41 +02002208 /*
2209 * Takes care of: New association with HT enable,
2210 * HT information change in beacon.
2211 */
2212 if (sta &&
2213 (changed & BSS_CHANGED_HT) &&
2214 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2215 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2216 if (ret < 0) {
2217 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002218 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002219 }
2220 ret = wl1271_acx_set_ht_information(wl,
2221 bss_conf->ht_operation_mode);
2222 if (ret < 0) {
2223 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002224 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002225 }
2226 }
2227 /*
2228 * Takes care of: New association without HT,
2229 * Disassociation.
2230 */
2231 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2232 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2233 if (ret < 0) {
2234 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002235 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002236 }
2237 }
2238
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002239 if (changed & BSS_CHANGED_ARP_FILTER) {
2240 __be32 addr = bss_conf->arp_addr_list[0];
2241 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2242
Eliad Pellerc5312772010-12-09 11:31:27 +02002243 if (bss_conf->arp_addr_cnt == 1 &&
2244 bss_conf->arp_filter_enabled) {
2245 /*
2246 * The template should have been configured only upon
2247 * association. however, it seems that the correct ip
2248 * isn't being set (when sending), so we have to
2249 * reconfigure the template upon every ip change.
2250 */
2251 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2252 if (ret < 0) {
2253 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002254 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002255 }
2256
2257 ret = wl1271_acx_arp_ip_filter(wl,
2258 (ACX_ARP_FILTER_ARP_FILTERING |
2259 ACX_ARP_FILTER_AUTO_ARP),
2260 addr);
2261 } else
2262 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002263
2264 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002265 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002266 }
2267
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002268 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002269 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002270 if (ret < 0) {
2271 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002272 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002273 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002274 }
2275
Arik Nemtsove78a2872010-10-16 19:07:21 +02002276out:
2277 return;
2278}
2279
2280static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2281 struct ieee80211_vif *vif,
2282 struct ieee80211_bss_conf *bss_conf,
2283 u32 changed)
2284{
2285 struct wl1271 *wl = hw->priv;
2286 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2287 int ret;
2288
2289 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2290 (int)changed);
2291
2292 mutex_lock(&wl->mutex);
2293
2294 if (unlikely(wl->state == WL1271_STATE_OFF))
2295 goto out;
2296
2297 ret = wl1271_ps_elp_wakeup(wl, false);
2298 if (ret < 0)
2299 goto out;
2300
2301 if (is_ap)
2302 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2303 else
2304 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2305
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306 wl1271_ps_elp_sleep(wl);
2307
2308out:
2309 mutex_unlock(&wl->mutex);
2310}
2311
Kalle Valoc6999d82010-02-18 13:25:41 +02002312static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2313 const struct ieee80211_tx_queue_params *params)
2314{
2315 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002316 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002317 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002318
2319 mutex_lock(&wl->mutex);
2320
2321 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2322
Kalle Valo4695dc92010-03-18 12:26:38 +02002323 if (params->uapsd)
2324 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2325 else
2326 ps_scheme = CONF_PS_SCHEME_LEGACY;
2327
Arik Nemtsov488fc542010-10-16 20:33:45 +02002328 if (wl->state == WL1271_STATE_OFF) {
2329 /*
2330 * If the state is off, the parameters will be recorded and
2331 * configured on init. This happens in AP-mode.
2332 */
2333 struct conf_tx_ac_category *conf_ac =
2334 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2335 struct conf_tx_tid *conf_tid =
2336 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2337
2338 conf_ac->ac = wl1271_tx_get_queue(queue);
2339 conf_ac->cw_min = (u8)params->cw_min;
2340 conf_ac->cw_max = params->cw_max;
2341 conf_ac->aifsn = params->aifs;
2342 conf_ac->tx_op_limit = params->txop << 5;
2343
2344 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2345 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2346 conf_tid->tsid = wl1271_tx_get_queue(queue);
2347 conf_tid->ps_scheme = ps_scheme;
2348 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2349 conf_tid->apsd_conf[0] = 0;
2350 conf_tid->apsd_conf[1] = 0;
2351 } else {
2352 ret = wl1271_ps_elp_wakeup(wl, false);
2353 if (ret < 0)
2354 goto out;
2355
2356 /*
2357 * the txop is confed in units of 32us by the mac80211,
2358 * we need us
2359 */
2360 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2361 params->cw_min, params->cw_max,
2362 params->aifs, params->txop << 5);
2363 if (ret < 0)
2364 goto out_sleep;
2365
2366 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2367 CONF_CHANNEL_TYPE_EDCF,
2368 wl1271_tx_get_queue(queue),
2369 ps_scheme, CONF_ACK_POLICY_LEGACY,
2370 0, 0);
2371 if (ret < 0)
2372 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002373
2374out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002375 wl1271_ps_elp_sleep(wl);
2376 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002377
2378out:
2379 mutex_unlock(&wl->mutex);
2380
2381 return ret;
2382}
2383
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002384static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2385{
2386
2387 struct wl1271 *wl = hw->priv;
2388 u64 mactime = ULLONG_MAX;
2389 int ret;
2390
2391 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2392
2393 mutex_lock(&wl->mutex);
2394
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002395 if (unlikely(wl->state == WL1271_STATE_OFF))
2396 goto out;
2397
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002398 ret = wl1271_ps_elp_wakeup(wl, false);
2399 if (ret < 0)
2400 goto out;
2401
2402 ret = wl1271_acx_tsf_info(wl, &mactime);
2403 if (ret < 0)
2404 goto out_sleep;
2405
2406out_sleep:
2407 wl1271_ps_elp_sleep(wl);
2408
2409out:
2410 mutex_unlock(&wl->mutex);
2411 return mactime;
2412}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002413
John W. Linvilleece550d2010-07-28 16:41:06 -04002414static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2415 struct survey_info *survey)
2416{
2417 struct wl1271 *wl = hw->priv;
2418 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002419
John W. Linvilleece550d2010-07-28 16:41:06 -04002420 if (idx != 0)
2421 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002422
John W. Linvilleece550d2010-07-28 16:41:06 -04002423 survey->channel = conf->channel;
2424 survey->filled = SURVEY_INFO_NOISE_DBM;
2425 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002426
John W. Linvilleece550d2010-07-28 16:41:06 -04002427 return 0;
2428}
2429
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002430static int wl1271_allocate_hlid(struct wl1271 *wl,
2431 struct ieee80211_sta *sta,
2432 u8 *hlid)
2433{
2434 struct wl1271_station *wl_sta;
2435 int id;
2436
2437 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2438 if (id >= AP_MAX_STATIONS) {
2439 wl1271_warning("could not allocate HLID - too much stations");
2440 return -EBUSY;
2441 }
2442
2443 wl_sta = (struct wl1271_station *)sta->drv_priv;
2444
2445 __set_bit(id, wl->ap_hlid_map);
2446 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2447 *hlid = wl_sta->hlid;
2448 return 0;
2449}
2450
2451static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2452{
2453 int id = hlid - WL1271_AP_STA_HLID_START;
2454
2455 __clear_bit(id, wl->ap_hlid_map);
2456}
2457
2458static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2459 struct ieee80211_vif *vif,
2460 struct ieee80211_sta *sta)
2461{
2462 struct wl1271 *wl = hw->priv;
2463 int ret = 0;
2464 u8 hlid;
2465
2466 mutex_lock(&wl->mutex);
2467
2468 if (unlikely(wl->state == WL1271_STATE_OFF))
2469 goto out;
2470
2471 if (wl->bss_type != BSS_TYPE_AP_BSS)
2472 goto out;
2473
2474 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2475
2476 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2477 if (ret < 0)
2478 goto out;
2479
2480 ret = wl1271_ps_elp_wakeup(wl, false);
2481 if (ret < 0)
2482 goto out;
2483
2484 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2485 if (ret < 0)
2486 goto out_sleep;
2487
2488out_sleep:
2489 wl1271_ps_elp_sleep(wl);
2490
2491out:
2492 mutex_unlock(&wl->mutex);
2493 return ret;
2494}
2495
2496static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2497 struct ieee80211_vif *vif,
2498 struct ieee80211_sta *sta)
2499{
2500 struct wl1271 *wl = hw->priv;
2501 struct wl1271_station *wl_sta;
2502 int ret = 0, id;
2503
2504 mutex_lock(&wl->mutex);
2505
2506 if (unlikely(wl->state == WL1271_STATE_OFF))
2507 goto out;
2508
2509 if (wl->bss_type != BSS_TYPE_AP_BSS)
2510 goto out;
2511
2512 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2513
2514 wl_sta = (struct wl1271_station *)sta->drv_priv;
2515 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2516 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2517 goto out;
2518
2519 ret = wl1271_ps_elp_wakeup(wl, false);
2520 if (ret < 0)
2521 goto out;
2522
2523 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2524 if (ret < 0)
2525 goto out_sleep;
2526
2527 wl1271_free_hlid(wl, wl_sta->hlid);
2528
2529out_sleep:
2530 wl1271_ps_elp_sleep(wl);
2531
2532out:
2533 mutex_unlock(&wl->mutex);
2534 return ret;
2535}
2536
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537/* can't be const, mac80211 writes to this */
2538static struct ieee80211_rate wl1271_rates[] = {
2539 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002540 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2541 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002543 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2544 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2546 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002547 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2548 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2550 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002551 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2552 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2554 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002555 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2556 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002558 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2559 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002561 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2562 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002564 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2565 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002567 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2568 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002570 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2571 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002573 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2574 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002576 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2577 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578};
2579
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002580/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002582 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002583 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002584 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2585 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2586 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002587 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002588 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2589 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2590 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002591 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002592 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2593 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2594 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002595};
2596
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002597/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002598static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002599 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002600 7, /* CONF_HW_RXTX_RATE_MCS7 */
2601 6, /* CONF_HW_RXTX_RATE_MCS6 */
2602 5, /* CONF_HW_RXTX_RATE_MCS5 */
2603 4, /* CONF_HW_RXTX_RATE_MCS4 */
2604 3, /* CONF_HW_RXTX_RATE_MCS3 */
2605 2, /* CONF_HW_RXTX_RATE_MCS2 */
2606 1, /* CONF_HW_RXTX_RATE_MCS1 */
2607 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002608
2609 11, /* CONF_HW_RXTX_RATE_54 */
2610 10, /* CONF_HW_RXTX_RATE_48 */
2611 9, /* CONF_HW_RXTX_RATE_36 */
2612 8, /* CONF_HW_RXTX_RATE_24 */
2613
2614 /* TI-specific rate */
2615 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2616
2617 7, /* CONF_HW_RXTX_RATE_18 */
2618 6, /* CONF_HW_RXTX_RATE_12 */
2619 3, /* CONF_HW_RXTX_RATE_11 */
2620 5, /* CONF_HW_RXTX_RATE_9 */
2621 4, /* CONF_HW_RXTX_RATE_6 */
2622 2, /* CONF_HW_RXTX_RATE_5_5 */
2623 1, /* CONF_HW_RXTX_RATE_2 */
2624 0 /* CONF_HW_RXTX_RATE_1 */
2625};
2626
Shahar Levie8b03a22010-10-13 16:09:39 +02002627/* 11n STA capabilities */
2628#define HW_RX_HIGHEST_RATE 72
2629
Shahar Levi00d20102010-11-08 11:20:10 +00002630#ifdef CONFIG_WL12XX_HT
2631#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002632 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2633 .ht_supported = true, \
2634 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2635 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2636 .mcs = { \
2637 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2638 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2639 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2640 }, \
2641}
Shahar Levi18357852010-10-13 16:09:41 +02002642#else
Shahar Levi00d20102010-11-08 11:20:10 +00002643#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002644 .ht_supported = false, \
2645}
2646#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002648/* can't be const, mac80211 writes to this */
2649static struct ieee80211_supported_band wl1271_band_2ghz = {
2650 .channels = wl1271_channels,
2651 .n_channels = ARRAY_SIZE(wl1271_channels),
2652 .bitrates = wl1271_rates,
2653 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002654 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002655};
2656
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002657/* 5 GHz data rates for WL1273 */
2658static struct ieee80211_rate wl1271_rates_5ghz[] = {
2659 { .bitrate = 60,
2660 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2661 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2662 { .bitrate = 90,
2663 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2664 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2665 { .bitrate = 120,
2666 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2667 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2668 { .bitrate = 180,
2669 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2670 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2671 { .bitrate = 240,
2672 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2673 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2674 { .bitrate = 360,
2675 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2676 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2677 { .bitrate = 480,
2678 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2679 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2680 { .bitrate = 540,
2681 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2682 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2683};
2684
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002685/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002686static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002687 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002688 { .hw_value = 8, .center_freq = 5040},
2689 { .hw_value = 9, .center_freq = 5045},
2690 { .hw_value = 11, .center_freq = 5055},
2691 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002692 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002693 { .hw_value = 34, .center_freq = 5170},
2694 { .hw_value = 36, .center_freq = 5180},
2695 { .hw_value = 38, .center_freq = 5190},
2696 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002697 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002698 { .hw_value = 44, .center_freq = 5220},
2699 { .hw_value = 46, .center_freq = 5230},
2700 { .hw_value = 48, .center_freq = 5240},
2701 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002702 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002703 { .hw_value = 60, .center_freq = 5300},
2704 { .hw_value = 64, .center_freq = 5320},
2705 { .hw_value = 100, .center_freq = 5500},
2706 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002707 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002708 { .hw_value = 112, .center_freq = 5560},
2709 { .hw_value = 116, .center_freq = 5580},
2710 { .hw_value = 120, .center_freq = 5600},
2711 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002712 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002713 { .hw_value = 132, .center_freq = 5660},
2714 { .hw_value = 136, .center_freq = 5680},
2715 { .hw_value = 140, .center_freq = 5700},
2716 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002717 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002718 { .hw_value = 157, .center_freq = 5785},
2719 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002720 { .hw_value = 165, .center_freq = 5825},
2721};
2722
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002723/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002724static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002725 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002726 7, /* CONF_HW_RXTX_RATE_MCS7 */
2727 6, /* CONF_HW_RXTX_RATE_MCS6 */
2728 5, /* CONF_HW_RXTX_RATE_MCS5 */
2729 4, /* CONF_HW_RXTX_RATE_MCS4 */
2730 3, /* CONF_HW_RXTX_RATE_MCS3 */
2731 2, /* CONF_HW_RXTX_RATE_MCS2 */
2732 1, /* CONF_HW_RXTX_RATE_MCS1 */
2733 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002734
2735 7, /* CONF_HW_RXTX_RATE_54 */
2736 6, /* CONF_HW_RXTX_RATE_48 */
2737 5, /* CONF_HW_RXTX_RATE_36 */
2738 4, /* CONF_HW_RXTX_RATE_24 */
2739
2740 /* TI-specific rate */
2741 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2742
2743 3, /* CONF_HW_RXTX_RATE_18 */
2744 2, /* CONF_HW_RXTX_RATE_12 */
2745 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2746 1, /* CONF_HW_RXTX_RATE_9 */
2747 0, /* CONF_HW_RXTX_RATE_6 */
2748 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2749 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2750 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2751};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002752
2753static struct ieee80211_supported_band wl1271_band_5ghz = {
2754 .channels = wl1271_channels_5ghz,
2755 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2756 .bitrates = wl1271_rates_5ghz,
2757 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002758 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002759};
2760
Tobias Klausera0ea9492010-05-20 10:38:11 +02002761static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002762 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2763 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2764};
2765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766static const struct ieee80211_ops wl1271_ops = {
2767 .start = wl1271_op_start,
2768 .stop = wl1271_op_stop,
2769 .add_interface = wl1271_op_add_interface,
2770 .remove_interface = wl1271_op_remove_interface,
2771 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002772 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002773 .configure_filter = wl1271_op_configure_filter,
2774 .tx = wl1271_op_tx,
2775 .set_key = wl1271_op_set_key,
2776 .hw_scan = wl1271_op_hw_scan,
2777 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002778 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002779 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002780 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002781 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002782 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002783 .sta_add = wl1271_op_sta_add,
2784 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002785 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002786};
2787
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002788
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002789u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002790{
2791 u8 idx;
2792
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002793 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002794
2795 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2796 wl1271_error("Illegal RX rate from HW: %d", rate);
2797 return 0;
2798 }
2799
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002800 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002801 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2802 wl1271_error("Unsupported RX rate from HW: %d", rate);
2803 return 0;
2804 }
2805
2806 return idx;
2807}
2808
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002809static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2810 struct device_attribute *attr,
2811 char *buf)
2812{
2813 struct wl1271 *wl = dev_get_drvdata(dev);
2814 ssize_t len;
2815
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002816 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002817
2818 mutex_lock(&wl->mutex);
2819 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2820 wl->sg_enabled);
2821 mutex_unlock(&wl->mutex);
2822
2823 return len;
2824
2825}
2826
2827static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2828 struct device_attribute *attr,
2829 const char *buf, size_t count)
2830{
2831 struct wl1271 *wl = dev_get_drvdata(dev);
2832 unsigned long res;
2833 int ret;
2834
2835 ret = strict_strtoul(buf, 10, &res);
2836
2837 if (ret < 0) {
2838 wl1271_warning("incorrect value written to bt_coex_mode");
2839 return count;
2840 }
2841
2842 mutex_lock(&wl->mutex);
2843
2844 res = !!res;
2845
2846 if (res == wl->sg_enabled)
2847 goto out;
2848
2849 wl->sg_enabled = res;
2850
2851 if (wl->state == WL1271_STATE_OFF)
2852 goto out;
2853
2854 ret = wl1271_ps_elp_wakeup(wl, false);
2855 if (ret < 0)
2856 goto out;
2857
2858 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2859 wl1271_ps_elp_sleep(wl);
2860
2861 out:
2862 mutex_unlock(&wl->mutex);
2863 return count;
2864}
2865
2866static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2867 wl1271_sysfs_show_bt_coex_state,
2868 wl1271_sysfs_store_bt_coex_state);
2869
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002870static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2871 struct device_attribute *attr,
2872 char *buf)
2873{
2874 struct wl1271 *wl = dev_get_drvdata(dev);
2875 ssize_t len;
2876
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002877 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002878
2879 mutex_lock(&wl->mutex);
2880 if (wl->hw_pg_ver >= 0)
2881 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2882 else
2883 len = snprintf(buf, len, "n/a\n");
2884 mutex_unlock(&wl->mutex);
2885
2886 return len;
2887}
2888
2889static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2890 wl1271_sysfs_show_hw_pg_ver, NULL);
2891
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002892int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002893{
2894 int ret;
2895
2896 if (wl->mac80211_registered)
2897 return 0;
2898
2899 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2900
2901 ret = ieee80211_register_hw(wl->hw);
2902 if (ret < 0) {
2903 wl1271_error("unable to register mac80211 hw: %d", ret);
2904 return ret;
2905 }
2906
2907 wl->mac80211_registered = true;
2908
Eliad Pellerd60080a2010-11-24 12:53:16 +02002909 wl1271_debugfs_init(wl);
2910
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002911 register_netdevice_notifier(&wl1271_dev_notifier);
2912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913 wl1271_notice("loaded");
2914
2915 return 0;
2916}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002917EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002919void wl1271_unregister_hw(struct wl1271 *wl)
2920{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002921 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002922 ieee80211_unregister_hw(wl->hw);
2923 wl->mac80211_registered = false;
2924
2925}
2926EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2927
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002928int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002930 static const u32 cipher_suites[] = {
2931 WLAN_CIPHER_SUITE_WEP40,
2932 WLAN_CIPHER_SUITE_WEP104,
2933 WLAN_CIPHER_SUITE_TKIP,
2934 WLAN_CIPHER_SUITE_CCMP,
2935 WL1271_CIPHER_SUITE_GEM,
2936 };
2937
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002938 /* The tx descriptor buffer and the TKIP space. */
2939 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2940 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941
2942 /* unit us */
2943 /* FIXME: find a proper value */
2944 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002945 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946
2947 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002948 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002949 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002950 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002951 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002952 IEEE80211_HW_CONNECTION_MONITOR |
2953 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002955 wl->hw->wiphy->cipher_suites = cipher_suites;
2956 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2957
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002958 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2959 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02002961 /*
2962 * Maximum length of elements in scanning probe request templates
2963 * should be the maximum length possible for a template, without
2964 * the IEEE80211 header of the template
2965 */
2966 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
2967 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03002969 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002970
Kalle Valo12bd8942010-03-18 12:26:33 +02002971 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002972 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002973
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01002974 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
2975
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002976 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002978 wl->hw->sta_data_size = sizeof(struct wl1271_station);
2979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 return 0;
2981}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002982EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002985
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002986struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002989 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002991 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02002992 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993
2994 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2995 if (!hw) {
2996 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002997 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002998 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 }
3000
Julia Lawall929ebd32010-05-15 23:16:39 +02003001 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003002 if (!plat_dev) {
3003 wl1271_error("could not allocate platform_device");
3004 ret = -ENOMEM;
3005 goto err_plat_alloc;
3006 }
3007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003008 wl = hw->priv;
3009 memset(wl, 0, sizeof(*wl));
3010
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003011 INIT_LIST_HEAD(&wl->list);
3012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003013 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003014 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003016 for (i = 0; i < NUM_TX_QUEUES; i++)
3017 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003019 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003020 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003021 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3022 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3023 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3024 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003026 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003029 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3030 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003031 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003033 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003034 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003035 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3036 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003037 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003038 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003039 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003040 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003041 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003042
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003043 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003044 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045 wl->tx_frames[i] = NULL;
3046
3047 spin_lock_init(&wl->wl_lock);
3048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049 wl->state = WL1271_STATE_OFF;
3050 mutex_init(&wl->mutex);
3051
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003052 /* Apply default driver configuration. */
3053 wl1271_conf_init(wl);
3054
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003055 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3056 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3057 if (!wl->aggr_buf) {
3058 ret = -ENOMEM;
3059 goto err_hw;
3060 }
3061
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003062 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003063 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003064 if (ret) {
3065 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003066 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003067 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003068 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003069
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003070 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003071 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003072 if (ret < 0) {
3073 wl1271_error("failed to create sysfs file bt_coex_state");
3074 goto err_platform;
3075 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003076
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003077 /* Create sysfs file to get HW PG version */
3078 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3079 if (ret < 0) {
3080 wl1271_error("failed to create sysfs file hw_pg_ver");
3081 goto err_bt_coex_state;
3082 }
3083
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003084 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003085
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003086err_bt_coex_state:
3087 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3088
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003089err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003090 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003091
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003092err_aggr:
3093 free_pages((unsigned long)wl->aggr_buf, order);
3094
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003095err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003096 wl1271_debugfs_exit(wl);
3097 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003098
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003099err_plat_alloc:
3100 ieee80211_free_hw(hw);
3101
3102err_hw_alloc:
3103
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003104 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003105}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003106EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003107
3108int wl1271_free_hw(struct wl1271 *wl)
3109{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003110 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003111 free_pages((unsigned long)wl->aggr_buf,
3112 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003113 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003114
3115 wl1271_debugfs_exit(wl);
3116
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003117 vfree(wl->fw);
3118 wl->fw = NULL;
3119 kfree(wl->nvs);
3120 wl->nvs = NULL;
3121
3122 kfree(wl->fw_status);
3123 kfree(wl->tx_res_if);
3124
3125 ieee80211_free_hw(wl->hw);
3126
3127 return 0;
3128}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003129EXPORT_SYMBOL_GPL(wl1271_free_hw);
3130
Eliad Peller17c17552010-12-12 12:15:35 +02003131u32 wl12xx_debug_level;
3132EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3133module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3134MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3135
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003136MODULE_LICENSE("GPL");
3137MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3138MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");