blob: a6de19a4ee0ef6654b2a50f34377b8dea893b406 [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);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200299static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200300
301
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200302static void wl1271_device_release(struct device *dev)
303{
304
305}
306
307static struct platform_device wl1271_device = {
308 .name = "wl1271",
309 .id = -1,
310
311 /* device model insists to have a release function */
312 .dev = {
313 .release = wl1271_device_release,
314 },
315};
316
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300317static LIST_HEAD(wl_list);
318
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300319static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
320 void *arg)
321{
322 struct net_device *dev = arg;
323 struct wireless_dev *wdev;
324 struct wiphy *wiphy;
325 struct ieee80211_hw *hw;
326 struct wl1271 *wl;
327 struct wl1271 *wl_temp;
328 int ret = 0;
329
330 /* Check that this notification is for us. */
331 if (what != NETDEV_CHANGE)
332 return NOTIFY_DONE;
333
334 wdev = dev->ieee80211_ptr;
335 if (wdev == NULL)
336 return NOTIFY_DONE;
337
338 wiphy = wdev->wiphy;
339 if (wiphy == NULL)
340 return NOTIFY_DONE;
341
342 hw = wiphy_priv(wiphy);
343 if (hw == NULL)
344 return NOTIFY_DONE;
345
346 wl_temp = hw->priv;
347 list_for_each_entry(wl, &wl_list, list) {
348 if (wl == wl_temp)
349 break;
350 }
351 if (wl != wl_temp)
352 return NOTIFY_DONE;
353
354 mutex_lock(&wl->mutex);
355
356 if (wl->state == WL1271_STATE_OFF)
357 goto out;
358
359 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
360 goto out;
361
362 ret = wl1271_ps_elp_wakeup(wl, false);
363 if (ret < 0)
364 goto out;
365
366 if ((dev->operstate == IF_OPER_UP) &&
367 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
368 wl1271_cmd_set_sta_state(wl);
369 wl1271_info("Association completed.");
370 }
371
372 wl1271_ps_elp_sleep(wl);
373
374out:
375 mutex_unlock(&wl->mutex);
376
377 return NOTIFY_OK;
378}
379
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100380static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200381 struct regulatory_request *request)
382{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100383 struct ieee80211_supported_band *band;
384 struct ieee80211_channel *ch;
385 int i;
386
387 band = wiphy->bands[IEEE80211_BAND_5GHZ];
388 for (i = 0; i < band->n_channels; i++) {
389 ch = &band->channels[i];
390 if (ch->flags & IEEE80211_CHAN_DISABLED)
391 continue;
392
393 if (ch->flags & IEEE80211_CHAN_RADAR)
394 ch->flags |= IEEE80211_CHAN_NO_IBSS |
395 IEEE80211_CHAN_PASSIVE_SCAN;
396
397 }
398
399 return 0;
400}
401
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300402static void wl1271_conf_init(struct wl1271 *wl)
403{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300404
405 /*
406 * This function applies the default configuration to the driver. This
407 * function is invoked upon driver load (spi probe.)
408 *
409 * The configuration is stored in a run-time structure in order to
410 * facilitate for run-time adjustment of any of the parameters. Making
411 * changes to the configuration structure will apply the new values on
412 * the next interface up (wl1271_op_start.)
413 */
414
415 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300416 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417}
418
419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420static int wl1271_plt_init(struct wl1271 *wl)
421{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200422 struct conf_tx_ac_category *conf_ac;
423 struct conf_tx_tid *conf_tid;
424 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200426 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200427 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200428 return ret;
429
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200430 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200431 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200432 return ret;
433
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200434 ret = wl1271_cmd_ext_radio_parms(wl);
435 if (ret < 0)
436 return ret;
437
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200438 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200439 if (ret < 0)
440 return ret;
441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 ret = wl1271_acx_init_mem_config(wl);
443 if (ret < 0)
444 return ret;
445
Luciano Coelho12419cc2010-02-18 13:25:44 +0200446 /* PHY layer config */
447 ret = wl1271_init_phy_config(wl);
448 if (ret < 0)
449 goto out_free_memmap;
450
451 ret = wl1271_acx_dco_itrim_params(wl);
452 if (ret < 0)
453 goto out_free_memmap;
454
455 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200456 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200457 if (ret < 0)
458 goto out_free_memmap;
459
460 /* Bluetooth WLAN coexistence */
461 ret = wl1271_init_pta(wl);
462 if (ret < 0)
463 goto out_free_memmap;
464
465 /* Energy detection */
466 ret = wl1271_init_energy_detection(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100471 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200475 /* Default TID/AC configuration */
476 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200477 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200478 conf_ac = &wl->conf.tx.ac_conf[i];
479 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
480 conf_ac->cw_max, conf_ac->aifsn,
481 conf_ac->tx_op_limit);
482 if (ret < 0)
483 goto out_free_memmap;
484
Luciano Coelho12419cc2010-02-18 13:25:44 +0200485 conf_tid = &wl->conf.tx.tid_conf[i];
486 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
487 conf_tid->channel_type,
488 conf_tid->tsid,
489 conf_tid->ps_scheme,
490 conf_tid->ack_policy,
491 conf_tid->apsd_conf[0],
492 conf_tid->apsd_conf[1]);
493 if (ret < 0)
494 goto out_free_memmap;
495 }
496
Luciano Coelho12419cc2010-02-18 13:25:44 +0200497 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200498 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200500 goto out_free_memmap;
501
502 /* Configure for CAM power saving (ie. always active) */
503 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
504 if (ret < 0)
505 goto out_free_memmap;
506
507 /* configure PM */
508 ret = wl1271_acx_pm_config(wl);
509 if (ret < 0)
510 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511
512 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200513
514 out_free_memmap:
515 kfree(wl->target_mem_map);
516 wl->target_mem_map = NULL;
517
518 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519}
520
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300521static void wl1271_fw_status(struct wl1271 *wl,
522 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200524 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525 u32 total = 0;
526 int i;
527
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200528 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529
530 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
531 "drv_rx_counter = %d, tx_results_counter = %d)",
532 status->intr,
533 status->fw_rx_counter,
534 status->drv_rx_counter,
535 status->tx_results_counter);
536
537 /* update number of available TX blocks */
538 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300539 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
540 wl->tx_blocks_freed[i];
541
542 wl->tx_blocks_freed[i] =
543 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544 wl->tx_blocks_available += cnt;
545 total += cnt;
546 }
547
Ido Yariva5225502010-10-12 14:49:10 +0200548 /* if more blocks are available now, tx work can be scheduled */
549 if (total)
550 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300551
552 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200553 getnstimeofday(&ts);
554 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
555 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556}
557
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200558#define WL1271_IRQ_MAX_LOOPS 10
559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560static void wl1271_irq_work(struct work_struct *work)
561{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300563 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200564 int loopcount = WL1271_IRQ_MAX_LOOPS;
565 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300566 struct wl1271 *wl =
567 container_of(work, struct wl1271, irq_work);
568
569 mutex_lock(&wl->mutex);
570
571 wl1271_debug(DEBUG_IRQ, "IRQ work");
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300574 goto out;
575
576 ret = wl1271_ps_elp_wakeup(wl, true);
577 if (ret < 0)
578 goto out;
579
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200580 spin_lock_irqsave(&wl->wl_lock, flags);
581 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
582 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
583 spin_unlock_irqrestore(&wl->wl_lock, flags);
584 loopcount--;
585
586 wl1271_fw_status(wl, wl->fw_status);
587 intr = le32_to_cpu(wl->fw_status->intr);
588 if (!intr) {
589 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200590 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200591 continue;
592 }
593
594 intr &= WL1271_INTR_MASK;
595
Eliad Pellerccc83b02010-10-27 14:09:57 +0200596 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
597 wl1271_error("watchdog interrupt received! "
598 "starting recovery.");
599 ieee80211_queue_work(wl->hw, &wl->recovery_work);
600
601 /* restarting the chip. ignore any other interrupt. */
602 goto out;
603 }
604
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 if (intr & WL1271_ACX_INTR_DATA) {
606 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
607
608 /* check for tx results */
609 if (wl->fw_status->tx_results_counter !=
610 (wl->tx_results_count & 0xff))
611 wl1271_tx_complete(wl);
612
Ido Yariva5225502010-10-12 14:49:10 +0200613 /* Check if any tx blocks were freed */
614 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200615 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200616 /*
617 * In order to avoid starvation of the TX path,
618 * call the work function directly.
619 */
620 wl1271_tx_work_locked(wl);
621 }
622
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200623 wl1271_rx(wl, wl->fw_status);
624 }
625
626 if (intr & WL1271_ACX_INTR_EVENT_A) {
627 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
628 wl1271_event_handle(wl, 0);
629 }
630
631 if (intr & WL1271_ACX_INTR_EVENT_B) {
632 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
633 wl1271_event_handle(wl, 1);
634 }
635
636 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
637 wl1271_debug(DEBUG_IRQ,
638 "WL1271_ACX_INTR_INIT_COMPLETE");
639
640 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
641 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
642
643 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644 }
645
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200646 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
647 ieee80211_queue_work(wl->hw, &wl->irq_work);
648 else
649 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
650 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652 wl1271_ps_elp_sleep(wl);
653
654out:
655 mutex_unlock(&wl->mutex);
656}
657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658static int wl1271_fetch_firmware(struct wl1271 *wl)
659{
660 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200661 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 int ret;
663
Arik Nemtsov166d5042010-10-16 21:44:57 +0200664 switch (wl->bss_type) {
665 case BSS_TYPE_AP_BSS:
666 fw_name = WL1271_AP_FW_NAME;
667 break;
668 case BSS_TYPE_IBSS:
669 case BSS_TYPE_STA_BSS:
670 fw_name = WL1271_FW_NAME;
671 break;
672 default:
673 wl1271_error("no compatible firmware for bss_type %d",
674 wl->bss_type);
675 return -EINVAL;
676 }
677
678 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
679
680 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681
682 if (ret < 0) {
683 wl1271_error("could not get firmware: %d", ret);
684 return ret;
685 }
686
687 if (fw->size % 4) {
688 wl1271_error("firmware size is not multiple of 32 bits: %zu",
689 fw->size);
690 ret = -EILSEQ;
691 goto out;
692 }
693
Arik Nemtsov166d5042010-10-16 21:44:57 +0200694 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300696 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697
698 if (!wl->fw) {
699 wl1271_error("could not allocate memory for the firmware");
700 ret = -ENOMEM;
701 goto out;
702 }
703
704 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200705 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 ret = 0;
707
708out:
709 release_firmware(fw);
710
711 return ret;
712}
713
714static int wl1271_fetch_nvs(struct wl1271 *wl)
715{
716 const struct firmware *fw;
717 int ret;
718
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200719 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720
721 if (ret < 0) {
722 wl1271_error("could not get nvs file: %d", ret);
723 return ret;
724 }
725
Julia Lawall929ebd32010-05-15 23:16:39 +0200726 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727
728 if (!wl->nvs) {
729 wl1271_error("could not allocate memory for the nvs file");
730 ret = -ENOMEM;
731 goto out;
732 }
733
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200734 wl->nvs_len = fw->size;
735
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736out:
737 release_firmware(fw);
738
739 return ret;
740}
741
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200742static void wl1271_recovery_work(struct work_struct *work)
743{
744 struct wl1271 *wl =
745 container_of(work, struct wl1271, recovery_work);
746
747 mutex_lock(&wl->mutex);
748
749 if (wl->state != WL1271_STATE_ON)
750 goto out;
751
752 wl1271_info("Hardware recovery in progress.");
753
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200754 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
755 ieee80211_connection_loss(wl->vif);
756
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200757 /* reboot the chipset */
758 __wl1271_op_remove_interface(wl);
759 ieee80211_restart_hw(wl->hw);
760
761out:
762 mutex_unlock(&wl->mutex);
763}
764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765static void wl1271_fw_wakeup(struct wl1271 *wl)
766{
767 u32 elp_reg;
768
769 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300770 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771}
772
773static int wl1271_setup(struct wl1271 *wl)
774{
775 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
776 if (!wl->fw_status)
777 return -ENOMEM;
778
779 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
780 if (!wl->tx_res_if) {
781 kfree(wl->fw_status);
782 return -ENOMEM;
783 }
784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 return 0;
786}
787
788static int wl1271_chip_wakeup(struct wl1271 *wl)
789{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300790 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 int ret = 0;
792
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200793 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200794 ret = wl1271_power_on(wl);
795 if (ret < 0)
796 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200798 wl1271_io_reset(wl);
799 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 /* We don't need a real memory partition here, because we only want
802 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300803 memset(&partition, 0, sizeof(partition));
804 partition.reg.start = REGISTERS_BASE;
805 partition.reg.size = REGISTERS_DOWN_SIZE;
806 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
808 /* ELP module wake up */
809 wl1271_fw_wakeup(wl);
810
811 /* whal_FwCtrl_BootSm() */
812
813 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200814 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815
816 /* 1. check if chip id is valid */
817
818 switch (wl->chip.id) {
819 case CHIP_ID_1271_PG10:
820 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
821 wl->chip.id);
822
823 ret = wl1271_setup(wl);
824 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200825 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 break;
827 case CHIP_ID_1271_PG20:
828 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
829 wl->chip.id);
830
831 ret = wl1271_setup(wl);
832 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200833 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 break;
835 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200836 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200838 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 }
840
Arik Nemtsov166d5042010-10-16 21:44:57 +0200841 /* Make sure the firmware type matches the BSS type */
842 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 ret = wl1271_fetch_firmware(wl);
844 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200845 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 }
847
848 /* No NVS from netlink, try to get it from the filesystem */
849 if (wl->nvs == NULL) {
850 ret = wl1271_fetch_nvs(wl);
851 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200852 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 }
854
855out:
856 return ret;
857}
858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859int wl1271_plt_start(struct wl1271 *wl)
860{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200861 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 int ret;
863
864 mutex_lock(&wl->mutex);
865
866 wl1271_notice("power up");
867
868 if (wl->state != WL1271_STATE_OFF) {
869 wl1271_error("cannot go into PLT state because not "
870 "in off state: %d", wl->state);
871 ret = -EBUSY;
872 goto out;
873 }
874
Arik Nemtsov166d5042010-10-16 21:44:57 +0200875 wl->bss_type = BSS_TYPE_STA_BSS;
876
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200877 while (retries) {
878 retries--;
879 ret = wl1271_chip_wakeup(wl);
880 if (ret < 0)
881 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200883 ret = wl1271_boot(wl);
884 if (ret < 0)
885 goto power_off;
886
887 ret = wl1271_plt_init(wl);
888 if (ret < 0)
889 goto irq_disable;
890
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200891 wl->state = WL1271_STATE_PLT;
892 wl1271_notice("firmware booted in PLT mode (%s)",
893 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 goto out;
895
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200896irq_disable:
897 wl1271_disable_interrupts(wl);
898 mutex_unlock(&wl->mutex);
899 /* Unlocking the mutex in the middle of handling is
900 inherently unsafe. In this case we deem it safe to do,
901 because we need to let any possibly pending IRQ out of
902 the system (and while we are WL1271_STATE_OFF the IRQ
903 work function will not do anything.) Also, any other
904 possible concurrent operations will fail due to the
905 current state, hence the wl1271 struct should be safe. */
906 cancel_work_sync(&wl->irq_work);
907 mutex_lock(&wl->mutex);
908power_off:
909 wl1271_power_off(wl);
910 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 wl1271_error("firmware boot in PLT mode failed despite %d retries",
913 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914out:
915 mutex_unlock(&wl->mutex);
916
917 return ret;
918}
919
920int wl1271_plt_stop(struct wl1271 *wl)
921{
922 int ret = 0;
923
924 mutex_lock(&wl->mutex);
925
926 wl1271_notice("power down");
927
928 if (wl->state != WL1271_STATE_PLT) {
929 wl1271_error("cannot power down because not in PLT "
930 "state: %d", wl->state);
931 ret = -EBUSY;
932 goto out;
933 }
934
935 wl1271_disable_interrupts(wl);
936 wl1271_power_off(wl);
937
938 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300939 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
941out:
942 mutex_unlock(&wl->mutex);
943
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200944 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200945 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200946
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 return ret;
948}
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
951{
952 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200953 struct ieee80211_conf *conf = &hw->conf;
954 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
955 struct ieee80211_sta *sta = txinfo->control.sta;
956 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200957 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
Shahar Levi18357852010-10-13 16:09:41 +0200959 /*
960 * peek into the rates configured in the STA entry.
961 * The rates set after connection stage, The first block only BG sets:
962 * the compare is for bit 0-16 of sta_rate_set. The second block add
963 * HT rates in case of HT supported.
964 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200965 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200966 if (sta &&
967 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200968 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
969 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200970 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
971 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
972 }
Shahar Levi18357852010-10-13 16:09:41 +0200973
Shahar Levi00d20102010-11-08 11:20:10 +0000974#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200975 if (sta &&
976 sta->ht_cap.ht_supported &&
977 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
978 sta->ht_cap.mcs.rx_mask[0])) {
979 /* Clean MCS bits before setting them */
980 wl->sta_rate_set &= HW_BG_RATES_MASK;
981 wl->sta_rate_set |=
982 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
983 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
984 }
985#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200986 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200987 spin_unlock_irqrestore(&wl->wl_lock, flags);
988
989 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200990 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
991 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992
993 /*
994 * The chip specific setup must run before the first TX packet -
995 * before that, the tx_work will not be initialized!
996 */
997
Ido Yariva5225502010-10-12 14:49:10 +0200998 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
999 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000
1001 /*
1002 * The workqueue is slow to process the tx_queue and we need stop
1003 * the queue here, otherwise the queue will get too long.
1004 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001005 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001006 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001008 spin_lock_irqsave(&wl->wl_lock, flags);
1009 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001010 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001011 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 }
1013
1014 return NETDEV_TX_OK;
1015}
1016
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001017static struct notifier_block wl1271_dev_notifier = {
1018 .notifier_call = wl1271_dev_notify,
1019};
1020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021static int wl1271_op_start(struct ieee80211_hw *hw)
1022{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001023 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1024
1025 /*
1026 * We have to delay the booting of the hardware because
1027 * we need to know the local MAC address before downloading and
1028 * initializing the firmware. The MAC address cannot be changed
1029 * after boot, and without the proper MAC address, the firmware
1030 * will not function properly.
1031 *
1032 * The MAC address is first known when the corresponding interface
1033 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001034 *
1035 * In addition, we currently have different firmwares for AP and managed
1036 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001037 */
1038
1039 return 0;
1040}
1041
1042static void wl1271_op_stop(struct ieee80211_hw *hw)
1043{
1044 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1045}
1046
1047static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1048 struct ieee80211_vif *vif)
1049{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001051 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001052 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001054 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001056 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1057 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
1059 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001060 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001061 wl1271_debug(DEBUG_MAC80211,
1062 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001063 ret = -EBUSY;
1064 goto out;
1065 }
1066
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001067 switch (vif->type) {
1068 case NL80211_IFTYPE_STATION:
1069 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001070 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001071 break;
1072 case NL80211_IFTYPE_ADHOC:
1073 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001074 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001075 break;
1076 default:
1077 ret = -EOPNOTSUPP;
1078 goto out;
1079 }
1080
1081 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082
1083 if (wl->state != WL1271_STATE_OFF) {
1084 wl1271_error("cannot start because not in off state: %d",
1085 wl->state);
1086 ret = -EBUSY;
1087 goto out;
1088 }
1089
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001090 while (retries) {
1091 retries--;
1092 ret = wl1271_chip_wakeup(wl);
1093 if (ret < 0)
1094 goto power_off;
1095
1096 ret = wl1271_boot(wl);
1097 if (ret < 0)
1098 goto power_off;
1099
1100 ret = wl1271_hw_init(wl);
1101 if (ret < 0)
1102 goto irq_disable;
1103
Eliad Peller71125ab2010-10-28 21:46:43 +02001104 booted = true;
1105 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001107irq_disable:
1108 wl1271_disable_interrupts(wl);
1109 mutex_unlock(&wl->mutex);
1110 /* Unlocking the mutex in the middle of handling is
1111 inherently unsafe. In this case we deem it safe to do,
1112 because we need to let any possibly pending IRQ out of
1113 the system (and while we are WL1271_STATE_OFF the IRQ
1114 work function will not do anything.) Also, any other
1115 possible concurrent operations will fail due to the
1116 current state, hence the wl1271 struct should be safe. */
1117 cancel_work_sync(&wl->irq_work);
1118 mutex_lock(&wl->mutex);
1119power_off:
1120 wl1271_power_off(wl);
1121 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122
Eliad Peller71125ab2010-10-28 21:46:43 +02001123 if (!booted) {
1124 wl1271_error("firmware boot failed despite %d retries",
1125 WL1271_BOOT_RETRIES);
1126 goto out;
1127 }
1128
1129 wl->vif = vif;
1130 wl->state = WL1271_STATE_ON;
1131 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1132
1133 /* update hw/fw version info in wiphy struct */
1134 wiphy->hw_version = wl->chip.id;
1135 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1136 sizeof(wiphy->fw_version));
1137
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001138 /*
1139 * Now we know if 11a is supported (info from the NVS), so disable
1140 * 11a channels if not supported
1141 */
1142 if (!wl->enable_11a)
1143 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1144
1145 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1146 wl->enable_11a ? "" : "not ");
1147
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001148out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001149 mutex_unlock(&wl->mutex);
1150
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001151 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001152 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001153
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 return ret;
1155}
1156
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001157static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001159 int i;
1160
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001161 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001163 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001165 list_del(&wl->list);
1166
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167 WARN_ON(wl->state != WL1271_STATE_ON);
1168
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001169 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001170 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001171 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001172
Luciano Coelho08688d62010-07-08 17:50:07 +03001173 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001174 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1175 kfree(wl->scan.scanned_ch);
1176 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001177 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001178 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179 }
1180
1181 wl->state = WL1271_STATE_OFF;
1182
1183 wl1271_disable_interrupts(wl);
1184
1185 mutex_unlock(&wl->mutex);
1186
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001187 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188 cancel_work_sync(&wl->irq_work);
1189 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001190 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001191 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192
1193 mutex_lock(&wl->mutex);
1194
1195 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001196 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001197 wl1271_power_off(wl);
1198
1199 memset(wl->bssid, 0, ETH_ALEN);
1200 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1201 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001203 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001204 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205
1206 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001207 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1209 wl->tx_blocks_available = 0;
1210 wl->tx_results_count = 0;
1211 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001212 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001213 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214 wl->time_offset = 0;
1215 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001216 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1217 wl->sta_rate_set = 0;
1218 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001219 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001220 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001221 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001222 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224 for (i = 0; i < NUM_TX_QUEUES; i++)
1225 wl->tx_blocks_freed[i] = 0;
1226
1227 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001228
1229 kfree(wl->fw_status);
1230 wl->fw_status = NULL;
1231 kfree(wl->tx_res_if);
1232 wl->tx_res_if = NULL;
1233 kfree(wl->target_mem_map);
1234 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001235}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001236
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001237static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1238 struct ieee80211_vif *vif)
1239{
1240 struct wl1271 *wl = hw->priv;
1241
1242 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001243 /*
1244 * wl->vif can be null here if someone shuts down the interface
1245 * just when hardware recovery has been started.
1246 */
1247 if (wl->vif) {
1248 WARN_ON(wl->vif != vif);
1249 __wl1271_op_remove_interface(wl);
1250 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001251
Juuso Oikarinen67353292010-11-18 15:19:02 +02001252 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254}
1255
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001256static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1257{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001258 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001259
1260 /* combine requested filters with current filter config */
1261 filters = wl->filters | filters;
1262
1263 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1264
1265 if (filters & FIF_PROMISC_IN_BSS) {
1266 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1267 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1268 wl->rx_config |= CFG_BSSID_FILTER_EN;
1269 }
1270 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1271 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1272 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1273 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1274 }
1275 if (filters & FIF_OTHER_BSS) {
1276 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1277 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1278 }
1279 if (filters & FIF_CONTROL) {
1280 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1281 wl->rx_filter |= CFG_RX_CTL_EN;
1282 }
1283 if (filters & FIF_FCSFAIL) {
1284 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1285 wl->rx_filter |= CFG_RX_FCS_ERROR;
1286 }
1287}
1288
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001289static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001290{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001291 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001292 /* we need to use a dummy BSSID for now */
1293 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1294 0xad, 0xbe, 0xef };
1295
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001296 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1297
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001298 /* pass through frames from all BSS */
1299 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1300
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001301 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001302 if (ret < 0)
1303 goto out;
1304
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001305 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001306
1307out:
1308 return ret;
1309}
1310
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001311static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001312{
1313 int ret;
1314
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001315 /*
1316 * One of the side effects of the JOIN command is that is clears
1317 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1318 * to a WPA/WPA2 access point will therefore kill the data-path.
1319 * Currently there is no supported scenario for JOIN during
1320 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1321 * must be handled somehow.
1322 *
1323 */
1324 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1325 wl1271_info("JOIN while associated.");
1326
1327 if (set_assoc)
1328 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1329
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001330 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1331 if (ret < 0)
1332 goto out;
1333
1334 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1335
1336 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1337 goto out;
1338
1339 /*
1340 * The join command disable the keep-alive mode, shut down its process,
1341 * and also clear the template config, so we need to reset it all after
1342 * the join. The acx_aid starts the keep-alive process, and the order
1343 * of the commands below is relevant.
1344 */
1345 ret = wl1271_acx_keep_alive_mode(wl, true);
1346 if (ret < 0)
1347 goto out;
1348
1349 ret = wl1271_acx_aid(wl, wl->aid);
1350 if (ret < 0)
1351 goto out;
1352
1353 ret = wl1271_cmd_build_klv_null_data(wl);
1354 if (ret < 0)
1355 goto out;
1356
1357 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1358 ACX_KEEP_ALIVE_TPL_VALID);
1359 if (ret < 0)
1360 goto out;
1361
1362out:
1363 return ret;
1364}
1365
1366static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001367{
1368 int ret;
1369
1370 /* to stop listening to a channel, we disconnect */
1371 ret = wl1271_cmd_disconnect(wl);
1372 if (ret < 0)
1373 goto out;
1374
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001375 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001376 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001377
1378 /* stop filterting packets based on bssid */
1379 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001380
1381out:
1382 return ret;
1383}
1384
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001385static void wl1271_set_band_rate(struct wl1271 *wl)
1386{
1387 if (wl->band == IEEE80211_BAND_2GHZ)
1388 wl->basic_rate_set = wl->conf.tx.basic_rate;
1389 else
1390 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1391}
1392
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001393static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001394{
1395 int ret;
1396
1397 if (idle) {
1398 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1399 ret = wl1271_unjoin(wl);
1400 if (ret < 0)
1401 goto out;
1402 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001403 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001404 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001405 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001406 if (ret < 0)
1407 goto out;
1408 ret = wl1271_acx_keep_alive_config(
1409 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1410 ACX_KEEP_ALIVE_TPL_INVALID);
1411 if (ret < 0)
1412 goto out;
1413 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1414 } else {
1415 /* increment the session counter */
1416 wl->session_counter++;
1417 if (wl->session_counter >= SESSION_COUNTER_MAX)
1418 wl->session_counter = 0;
1419 ret = wl1271_dummy_join(wl);
1420 if (ret < 0)
1421 goto out;
1422 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1423 }
1424
1425out:
1426 return ret;
1427}
1428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1430{
1431 struct wl1271 *wl = hw->priv;
1432 struct ieee80211_conf *conf = &hw->conf;
1433 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001434 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435
1436 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1437
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001438 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1439 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 channel,
1441 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001442 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001443 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1444 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001446 /*
1447 * mac80211 will go to idle nearly immediately after transmitting some
1448 * frames, such as the deauth. To make sure those frames reach the air,
1449 * wait here until the TX queue is fully flushed.
1450 */
1451 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1452 (conf->flags & IEEE80211_CONF_IDLE))
1453 wl1271_tx_flush(wl);
1454
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 mutex_lock(&wl->mutex);
1456
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001457 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1458 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001459 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001460 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001461
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001462 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1463
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 ret = wl1271_ps_elp_wakeup(wl, false);
1465 if (ret < 0)
1466 goto out;
1467
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001468 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001469 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1470 ((wl->band != conf->channel->band) ||
1471 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001472 wl->band = conf->channel->band;
1473 wl->channel = channel;
1474
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001475 if (!is_ap) {
1476 /*
1477 * FIXME: the mac80211 should really provide a fixed
1478 * rate to use here. for now, just use the smallest
1479 * possible rate for the band as a fixed rate for
1480 * association frames and other control messages.
1481 */
1482 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1483 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001484
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001485 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1486 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001487 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001488 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001489 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001490
1491 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1492 ret = wl1271_join(wl, false);
1493 if (ret < 0)
1494 wl1271_warning("cmd join on channel "
1495 "failed %d", ret);
1496 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001497 }
1498 }
1499
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001500 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1501 ret = wl1271_sta_handle_idle(wl,
1502 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001503 if (ret < 0)
1504 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505 }
1506
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001507 /*
1508 * if mac80211 changes the PSM mode, make sure the mode is not
1509 * incorrectly changed after the pspoll failure active window.
1510 */
1511 if (changed & IEEE80211_CONF_CHANGE_PS)
1512 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1513
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001514 if (conf->flags & IEEE80211_CONF_PS &&
1515 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1516 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
1518 /*
1519 * We enter PSM only if we're already associated.
1520 * If we're not, we'll enter it when joining an SSID,
1521 * through the bss_info_changed() hook.
1522 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001523 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001524 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001525 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001526 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001527 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001529 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001530 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001532 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001534 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001535 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001536 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537 }
1538
1539 if (conf->power_level != wl->power_level) {
1540 ret = wl1271_acx_tx_power(wl, conf->power_level);
1541 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001542 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543
1544 wl->power_level = conf->power_level;
1545 }
1546
1547out_sleep:
1548 wl1271_ps_elp_sleep(wl);
1549
1550out:
1551 mutex_unlock(&wl->mutex);
1552
1553 return ret;
1554}
1555
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001556struct wl1271_filter_params {
1557 bool enabled;
1558 int mc_list_length;
1559 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1560};
1561
Jiri Pirko22bedad2010-04-01 21:22:57 +00001562static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1563 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001564{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001565 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001566 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001567 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001569 if (unlikely(wl->state == WL1271_STATE_OFF))
1570 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001571
Juuso Oikarinen74441132009-10-13 12:47:53 +03001572 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001573 if (!fp) {
1574 wl1271_error("Out of memory setting filters.");
1575 return 0;
1576 }
1577
1578 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001579 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001580 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1581 fp->enabled = false;
1582 } else {
1583 fp->enabled = true;
1584 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001585 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001586 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001587 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001588 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001589 }
1590
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001591 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001592}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001594#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1595 FIF_ALLMULTI | \
1596 FIF_FCSFAIL | \
1597 FIF_BCN_PRBRESP_PROMISC | \
1598 FIF_CONTROL | \
1599 FIF_OTHER_BSS)
1600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1602 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001603 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001605 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001607 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608
Arik Nemtsov7d057862010-10-16 19:25:35 +02001609 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1610 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001612 mutex_lock(&wl->mutex);
1613
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001614 *total &= WL1271_SUPPORTED_FILTERS;
1615 changed &= WL1271_SUPPORTED_FILTERS;
1616
1617 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001618 goto out;
1619
1620 ret = wl1271_ps_elp_wakeup(wl, false);
1621 if (ret < 0)
1622 goto out;
1623
Arik Nemtsov7d057862010-10-16 19:25:35 +02001624 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1625 if (*total & FIF_ALLMULTI)
1626 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1627 else if (fp)
1628 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1629 fp->mc_list,
1630 fp->mc_list_length);
1631 if (ret < 0)
1632 goto out_sleep;
1633 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001634
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001635 /* determine, whether supported filter values have changed */
1636 if (changed == 0)
1637 goto out_sleep;
1638
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001639 /* configure filters */
1640 wl->filters = *total;
1641 wl1271_configure_filters(wl, 0);
1642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001643 /* apply configured filters */
1644 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1645 if (ret < 0)
1646 goto out_sleep;
1647
1648out_sleep:
1649 wl1271_ps_elp_sleep(wl);
1650
1651out:
1652 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001653 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654}
1655
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001656static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1657 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1658 u16 tx_seq_16)
1659{
1660 struct wl1271_ap_key *ap_key;
1661 int i;
1662
1663 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1664
1665 if (key_size > MAX_KEY_SIZE)
1666 return -EINVAL;
1667
1668 /*
1669 * Find next free entry in ap_keys. Also check we are not replacing
1670 * an existing key.
1671 */
1672 for (i = 0; i < MAX_NUM_KEYS; i++) {
1673 if (wl->recorded_ap_keys[i] == NULL)
1674 break;
1675
1676 if (wl->recorded_ap_keys[i]->id == id) {
1677 wl1271_warning("trying to record key replacement");
1678 return -EINVAL;
1679 }
1680 }
1681
1682 if (i == MAX_NUM_KEYS)
1683 return -EBUSY;
1684
1685 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1686 if (!ap_key)
1687 return -ENOMEM;
1688
1689 ap_key->id = id;
1690 ap_key->key_type = key_type;
1691 ap_key->key_size = key_size;
1692 memcpy(ap_key->key, key, key_size);
1693 ap_key->hlid = hlid;
1694 ap_key->tx_seq_32 = tx_seq_32;
1695 ap_key->tx_seq_16 = tx_seq_16;
1696
1697 wl->recorded_ap_keys[i] = ap_key;
1698 return 0;
1699}
1700
1701static void wl1271_free_ap_keys(struct wl1271 *wl)
1702{
1703 int i;
1704
1705 for (i = 0; i < MAX_NUM_KEYS; i++) {
1706 kfree(wl->recorded_ap_keys[i]);
1707 wl->recorded_ap_keys[i] = NULL;
1708 }
1709}
1710
1711static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1712{
1713 int i, ret = 0;
1714 struct wl1271_ap_key *key;
1715 bool wep_key_added = false;
1716
1717 for (i = 0; i < MAX_NUM_KEYS; i++) {
1718 if (wl->recorded_ap_keys[i] == NULL)
1719 break;
1720
1721 key = wl->recorded_ap_keys[i];
1722 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1723 key->id, key->key_type,
1724 key->key_size, key->key,
1725 key->hlid, key->tx_seq_32,
1726 key->tx_seq_16);
1727 if (ret < 0)
1728 goto out;
1729
1730 if (key->key_type == KEY_WEP)
1731 wep_key_added = true;
1732 }
1733
1734 if (wep_key_added) {
1735 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1736 if (ret < 0)
1737 goto out;
1738 }
1739
1740out:
1741 wl1271_free_ap_keys(wl);
1742 return ret;
1743}
1744
1745static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1746 u8 key_size, const u8 *key, u32 tx_seq_32,
1747 u16 tx_seq_16, struct ieee80211_sta *sta)
1748{
1749 int ret;
1750 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1751
1752 if (is_ap) {
1753 struct wl1271_station *wl_sta;
1754 u8 hlid;
1755
1756 if (sta) {
1757 wl_sta = (struct wl1271_station *)sta->drv_priv;
1758 hlid = wl_sta->hlid;
1759 } else {
1760 hlid = WL1271_AP_BROADCAST_HLID;
1761 }
1762
1763 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1764 /*
1765 * We do not support removing keys after AP shutdown.
1766 * Pretend we do to make mac80211 happy.
1767 */
1768 if (action != KEY_ADD_OR_REPLACE)
1769 return 0;
1770
1771 ret = wl1271_record_ap_key(wl, id,
1772 key_type, key_size,
1773 key, hlid, tx_seq_32,
1774 tx_seq_16);
1775 } else {
1776 ret = wl1271_cmd_set_ap_key(wl, action,
1777 id, key_type, key_size,
1778 key, hlid, tx_seq_32,
1779 tx_seq_16);
1780 }
1781
1782 if (ret < 0)
1783 return ret;
1784 } else {
1785 const u8 *addr;
1786 static const u8 bcast_addr[ETH_ALEN] = {
1787 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1788 };
1789
1790 addr = sta ? sta->addr : bcast_addr;
1791
1792 if (is_zero_ether_addr(addr)) {
1793 /* We dont support TX only encryption */
1794 return -EOPNOTSUPP;
1795 }
1796
1797 /* The wl1271 does not allow to remove unicast keys - they
1798 will be cleared automatically on next CMD_JOIN. Ignore the
1799 request silently, as we dont want the mac80211 to emit
1800 an error message. */
1801 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1802 return 0;
1803
1804 ret = wl1271_cmd_set_sta_key(wl, action,
1805 id, key_type, key_size,
1806 key, addr, tx_seq_32,
1807 tx_seq_16);
1808 if (ret < 0)
1809 return ret;
1810
1811 /* the default WEP key needs to be configured at least once */
1812 if (key_type == KEY_WEP) {
1813 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1814 wl->default_key);
1815 if (ret < 0)
1816 return ret;
1817 }
1818 }
1819
1820 return 0;
1821}
1822
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1824 struct ieee80211_vif *vif,
1825 struct ieee80211_sta *sta,
1826 struct ieee80211_key_conf *key_conf)
1827{
1828 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001830 u32 tx_seq_32 = 0;
1831 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 u8 key_type;
1833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1835
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001836 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001838 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 key_conf->keylen, key_conf->flags);
1840 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 mutex_lock(&wl->mutex);
1843
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001844 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1845 ret = -EAGAIN;
1846 goto out_unlock;
1847 }
1848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 ret = wl1271_ps_elp_wakeup(wl, false);
1850 if (ret < 0)
1851 goto out_unlock;
1852
Johannes Berg97359d12010-08-10 09:46:38 +02001853 switch (key_conf->cipher) {
1854 case WLAN_CIPHER_SUITE_WEP40:
1855 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 key_type = KEY_WEP;
1857
1858 key_conf->hw_key_idx = key_conf->keyidx;
1859 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001860 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 key_type = KEY_TKIP;
1862
1863 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001864 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1865 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001867 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 key_type = KEY_AES;
1869
1870 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001871 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1872 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001874 case WL1271_CIPHER_SUITE_GEM:
1875 key_type = KEY_GEM;
1876 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1877 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1878 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001879 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001880 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881
1882 ret = -EOPNOTSUPP;
1883 goto out_sleep;
1884 }
1885
1886 switch (cmd) {
1887 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001888 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1889 key_conf->keyidx, key_type,
1890 key_conf->keylen, key_conf->key,
1891 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001892 if (ret < 0) {
1893 wl1271_error("Could not add or replace key");
1894 goto out_sleep;
1895 }
1896 break;
1897
1898 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001899 ret = wl1271_set_key(wl, KEY_REMOVE,
1900 key_conf->keyidx, key_type,
1901 key_conf->keylen, key_conf->key,
1902 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 if (ret < 0) {
1904 wl1271_error("Could not remove key");
1905 goto out_sleep;
1906 }
1907 break;
1908
1909 default:
1910 wl1271_error("Unsupported key cmd 0x%x", cmd);
1911 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912 break;
1913 }
1914
1915out_sleep:
1916 wl1271_ps_elp_sleep(wl);
1917
1918out_unlock:
1919 mutex_unlock(&wl->mutex);
1920
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 return ret;
1922}
1923
1924static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001925 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 struct cfg80211_scan_request *req)
1927{
1928 struct wl1271 *wl = hw->priv;
1929 int ret;
1930 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001931 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932
1933 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1934
1935 if (req->n_ssids) {
1936 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001937 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938 }
1939
1940 mutex_lock(&wl->mutex);
1941
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001942 if (wl->state == WL1271_STATE_OFF) {
1943 /*
1944 * We cannot return -EBUSY here because cfg80211 will expect
1945 * a call to ieee80211_scan_completed if we do - in this case
1946 * there won't be any call.
1947 */
1948 ret = -EAGAIN;
1949 goto out;
1950 }
1951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 ret = wl1271_ps_elp_wakeup(wl, false);
1953 if (ret < 0)
1954 goto out;
1955
Luciano Coelho5924f892010-08-04 03:46:22 +03001956 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957
1958 wl1271_ps_elp_sleep(wl);
1959
1960out:
1961 mutex_unlock(&wl->mutex);
1962
1963 return ret;
1964}
1965
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001966static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1967{
1968 struct wl1271 *wl = hw->priv;
1969 int ret = 0;
1970
1971 mutex_lock(&wl->mutex);
1972
1973 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1974 ret = -EAGAIN;
1975 goto out;
1976 }
1977
1978 ret = wl1271_ps_elp_wakeup(wl, false);
1979 if (ret < 0)
1980 goto out;
1981
1982 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1983 if (ret < 0)
1984 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1985
1986 wl1271_ps_elp_sleep(wl);
1987
1988out:
1989 mutex_unlock(&wl->mutex);
1990
1991 return ret;
1992}
1993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1995{
1996 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001997 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998
1999 mutex_lock(&wl->mutex);
2000
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002001 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2002 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002003 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002004 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 ret = wl1271_ps_elp_wakeup(wl, false);
2007 if (ret < 0)
2008 goto out;
2009
2010 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2011 if (ret < 0)
2012 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2013
2014 wl1271_ps_elp_sleep(wl);
2015
2016out:
2017 mutex_unlock(&wl->mutex);
2018
2019 return ret;
2020}
2021
Arik Nemtsove78a2872010-10-16 19:07:21 +02002022static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002023 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002024{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002025 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002026
2027 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002028 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002029 if (ptr[0] == WLAN_EID_SSID) {
2030 wl->ssid_len = ptr[1];
2031 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002032 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002033 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002034 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002035 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002036
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002037 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002038 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002039}
2040
Arik Nemtsove78a2872010-10-16 19:07:21 +02002041static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2042 struct ieee80211_bss_conf *bss_conf,
2043 u32 changed)
2044{
2045 int ret = 0;
2046
2047 if (changed & BSS_CHANGED_ERP_SLOT) {
2048 if (bss_conf->use_short_slot)
2049 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2050 else
2051 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2052 if (ret < 0) {
2053 wl1271_warning("Set slot time failed %d", ret);
2054 goto out;
2055 }
2056 }
2057
2058 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2059 if (bss_conf->use_short_preamble)
2060 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2061 else
2062 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2063 }
2064
2065 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2066 if (bss_conf->use_cts_prot)
2067 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2068 else
2069 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2070 if (ret < 0) {
2071 wl1271_warning("Set ctsprotect failed %d", ret);
2072 goto out;
2073 }
2074 }
2075
2076out:
2077 return ret;
2078}
2079
2080static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2081 struct ieee80211_vif *vif,
2082 struct ieee80211_bss_conf *bss_conf,
2083 u32 changed)
2084{
2085 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2086 int ret = 0;
2087
2088 if ((changed & BSS_CHANGED_BEACON_INT)) {
2089 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2090 bss_conf->beacon_int);
2091
2092 wl->beacon_int = bss_conf->beacon_int;
2093 }
2094
2095 if ((changed & BSS_CHANGED_BEACON)) {
2096 struct ieee80211_hdr *hdr;
2097 int ieoffset = offsetof(struct ieee80211_mgmt,
2098 u.beacon.variable);
2099 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2100 u16 tmpl_id;
2101
2102 if (!beacon)
2103 goto out;
2104
2105 wl1271_debug(DEBUG_MASTER, "beacon updated");
2106
2107 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2108 if (ret < 0) {
2109 dev_kfree_skb(beacon);
2110 goto out;
2111 }
2112 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2113 CMD_TEMPL_BEACON;
2114 ret = wl1271_cmd_template_set(wl, tmpl_id,
2115 beacon->data,
2116 beacon->len, 0,
2117 wl1271_tx_min_rate_get(wl));
2118 if (ret < 0) {
2119 dev_kfree_skb(beacon);
2120 goto out;
2121 }
2122
2123 hdr = (struct ieee80211_hdr *) beacon->data;
2124 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2125 IEEE80211_STYPE_PROBE_RESP);
2126
2127 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2128 CMD_TEMPL_PROBE_RESPONSE;
2129 ret = wl1271_cmd_template_set(wl,
2130 tmpl_id,
2131 beacon->data,
2132 beacon->len, 0,
2133 wl1271_tx_min_rate_get(wl));
2134 dev_kfree_skb(beacon);
2135 if (ret < 0)
2136 goto out;
2137 }
2138
2139out:
2140 return ret;
2141}
2142
2143/* AP mode changes */
2144static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 struct ieee80211_vif *vif,
2146 struct ieee80211_bss_conf *bss_conf,
2147 u32 changed)
2148{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002149 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150
Arik Nemtsove78a2872010-10-16 19:07:21 +02002151 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2152 u32 rates = bss_conf->basic_rates;
2153 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2156 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2157 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2158 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Arik Nemtsove78a2872010-10-16 19:07:21 +02002160 /* update the AP management rate policy with the new rates */
2161 mgmt_rc.enabled_rates = wl->basic_rate_set;
2162 mgmt_rc.long_retry_limit = 10;
2163 mgmt_rc.short_retry_limit = 10;
2164 mgmt_rc.aflags = 0;
2165 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2166 ACX_TX_AP_MODE_MGMT_RATE);
2167 if (ret < 0) {
2168 wl1271_error("AP mgmt policy change failed %d", ret);
2169 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002170 }
2171 }
2172
Arik Nemtsove78a2872010-10-16 19:07:21 +02002173 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2174 if (ret < 0)
2175 goto out;
2176
2177 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2178 if (bss_conf->enable_beacon) {
2179 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2180 ret = wl1271_cmd_start_bss(wl);
2181 if (ret < 0)
2182 goto out;
2183
2184 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2185 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002186
2187 ret = wl1271_ap_init_hwenc(wl);
2188 if (ret < 0)
2189 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002190 }
2191 } else {
2192 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2193 ret = wl1271_cmd_stop_bss(wl);
2194 if (ret < 0)
2195 goto out;
2196
2197 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2198 wl1271_debug(DEBUG_AP, "stopped AP");
2199 }
2200 }
2201 }
2202
2203 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2204 if (ret < 0)
2205 goto out;
2206out:
2207 return;
2208}
2209
2210/* STA/IBSS mode changes */
2211static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2212 struct ieee80211_vif *vif,
2213 struct ieee80211_bss_conf *bss_conf,
2214 u32 changed)
2215{
2216 bool do_join = false, set_assoc = false;
2217 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2218 int ret;
2219 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2220
2221 if (is_ibss) {
2222 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2223 changed);
2224 if (ret < 0)
2225 goto out;
2226 }
2227
2228 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2229 do_join = true;
2230
2231 /* Need to update the SSID (for filtering etc) */
2232 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2233 do_join = true;
2234
2235 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002236 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2237 bss_conf->enable_beacon ? "enabled" : "disabled");
2238
2239 if (bss_conf->enable_beacon)
2240 wl->set_bss_type = BSS_TYPE_IBSS;
2241 else
2242 wl->set_bss_type = BSS_TYPE_STA_BSS;
2243 do_join = true;
2244 }
2245
Arik Nemtsove78a2872010-10-16 19:07:21 +02002246 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002247 bool enable = false;
2248 if (bss_conf->cqm_rssi_thold)
2249 enable = true;
2250 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2251 bss_conf->cqm_rssi_thold,
2252 bss_conf->cqm_rssi_hyst);
2253 if (ret < 0)
2254 goto out;
2255 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2256 }
2257
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002258 if ((changed & BSS_CHANGED_BSSID) &&
2259 /*
2260 * Now we know the correct bssid, so we send a new join command
2261 * and enable the BSSID filter
2262 */
2263 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002264 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002265
Arik Nemtsove78a2872010-10-16 19:07:21 +02002266 ret = wl1271_cmd_build_null_data(wl);
2267 if (ret < 0)
2268 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002269
Arik Nemtsove78a2872010-10-16 19:07:21 +02002270 ret = wl1271_build_qos_null_data(wl);
2271 if (ret < 0)
2272 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002273
Arik Nemtsove78a2872010-10-16 19:07:21 +02002274 /* filter out all packets not from this BSSID */
2275 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002276
Arik Nemtsove78a2872010-10-16 19:07:21 +02002277 /* Need to update the BSSID (for filtering etc) */
2278 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002279 }
2280
Arik Nemtsove78a2872010-10-16 19:07:21 +02002281 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002282 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002283 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002284 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002285 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002286 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002288 wl->ps_poll_failures = 0;
2289
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002290 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002291 * use basic rates from AP, and determine lowest rate
2292 * to use with control frames.
2293 */
2294 rates = bss_conf->basic_rates;
2295 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2296 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002297 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002298 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002299 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002300 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002301
2302 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002303 * with wl1271, we don't need to update the
2304 * beacon_int and dtim_period, because the firmware
2305 * updates it by itself when the first beacon is
2306 * received after a join.
2307 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2309 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002310 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002312 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002313 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002314 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002315 dev_kfree_skb(wl->probereq);
2316 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2317 ieoffset = offsetof(struct ieee80211_mgmt,
2318 u.probe_req.variable);
2319 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002320
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002321 /* enable the connection monitoring feature */
2322 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002324 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002325
2326 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002327 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2328 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002329 enum wl1271_cmd_ps_mode mode;
2330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002332 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002333 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002334 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002336 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002338 } else {
2339 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002340 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002341 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002342 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002343
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002344 /* free probe-request template */
2345 dev_kfree_skb(wl->probereq);
2346 wl->probereq = NULL;
2347
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002348 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002349 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002350
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002351 /* revert back to minimum rates for the current band */
2352 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002353 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002354 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002355 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002356 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002357
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002358 /* disable connection monitor features */
2359 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002360
2361 /* Disable the keep-alive feature */
2362 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002363 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002364 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002365
2366 /* restore the bssid filter and go to dummy bssid */
2367 wl1271_unjoin(wl);
2368 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369 }
2370 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002371
Arik Nemtsove78a2872010-10-16 19:07:21 +02002372 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2373 if (ret < 0)
2374 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375
Shahar Levi18357852010-10-13 16:09:41 +02002376 /*
2377 * Takes care of: New association with HT enable,
2378 * HT information change in beacon.
2379 */
2380 if (sta &&
2381 (changed & BSS_CHANGED_HT) &&
2382 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2383 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2384 if (ret < 0) {
2385 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002386 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002387 }
2388 ret = wl1271_acx_set_ht_information(wl,
2389 bss_conf->ht_operation_mode);
2390 if (ret < 0) {
2391 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002392 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002393 }
2394 }
2395 /*
2396 * Takes care of: New association without HT,
2397 * Disassociation.
2398 */
2399 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2400 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2401 if (ret < 0) {
2402 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002403 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002404 }
2405 }
2406
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002407 if (changed & BSS_CHANGED_ARP_FILTER) {
2408 __be32 addr = bss_conf->arp_addr_list[0];
2409 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2410
Eliad Pellerc5312772010-12-09 11:31:27 +02002411 if (bss_conf->arp_addr_cnt == 1 &&
2412 bss_conf->arp_filter_enabled) {
2413 /*
2414 * The template should have been configured only upon
2415 * association. however, it seems that the correct ip
2416 * isn't being set (when sending), so we have to
2417 * reconfigure the template upon every ip change.
2418 */
2419 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2420 if (ret < 0) {
2421 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002422 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002423 }
2424
2425 ret = wl1271_acx_arp_ip_filter(wl,
2426 (ACX_ARP_FILTER_ARP_FILTERING |
2427 ACX_ARP_FILTER_AUTO_ARP),
2428 addr);
2429 } else
2430 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002431
2432 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002433 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002434 }
2435
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002436 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002437 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002438 if (ret < 0) {
2439 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002440 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002441 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002442 }
2443
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444out:
2445 return;
2446}
2447
2448static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2449 struct ieee80211_vif *vif,
2450 struct ieee80211_bss_conf *bss_conf,
2451 u32 changed)
2452{
2453 struct wl1271 *wl = hw->priv;
2454 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2455 int ret;
2456
2457 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2458 (int)changed);
2459
2460 mutex_lock(&wl->mutex);
2461
2462 if (unlikely(wl->state == WL1271_STATE_OFF))
2463 goto out;
2464
2465 ret = wl1271_ps_elp_wakeup(wl, false);
2466 if (ret < 0)
2467 goto out;
2468
2469 if (is_ap)
2470 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2471 else
2472 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474 wl1271_ps_elp_sleep(wl);
2475
2476out:
2477 mutex_unlock(&wl->mutex);
2478}
2479
Kalle Valoc6999d82010-02-18 13:25:41 +02002480static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2481 const struct ieee80211_tx_queue_params *params)
2482{
2483 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002484 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002485 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002486
2487 mutex_lock(&wl->mutex);
2488
2489 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2490
Kalle Valo4695dc92010-03-18 12:26:38 +02002491 if (params->uapsd)
2492 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2493 else
2494 ps_scheme = CONF_PS_SCHEME_LEGACY;
2495
Arik Nemtsov488fc542010-10-16 20:33:45 +02002496 if (wl->state == WL1271_STATE_OFF) {
2497 /*
2498 * If the state is off, the parameters will be recorded and
2499 * configured on init. This happens in AP-mode.
2500 */
2501 struct conf_tx_ac_category *conf_ac =
2502 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2503 struct conf_tx_tid *conf_tid =
2504 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2505
2506 conf_ac->ac = wl1271_tx_get_queue(queue);
2507 conf_ac->cw_min = (u8)params->cw_min;
2508 conf_ac->cw_max = params->cw_max;
2509 conf_ac->aifsn = params->aifs;
2510 conf_ac->tx_op_limit = params->txop << 5;
2511
2512 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2513 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2514 conf_tid->tsid = wl1271_tx_get_queue(queue);
2515 conf_tid->ps_scheme = ps_scheme;
2516 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2517 conf_tid->apsd_conf[0] = 0;
2518 conf_tid->apsd_conf[1] = 0;
2519 } else {
2520 ret = wl1271_ps_elp_wakeup(wl, false);
2521 if (ret < 0)
2522 goto out;
2523
2524 /*
2525 * the txop is confed in units of 32us by the mac80211,
2526 * we need us
2527 */
2528 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2529 params->cw_min, params->cw_max,
2530 params->aifs, params->txop << 5);
2531 if (ret < 0)
2532 goto out_sleep;
2533
2534 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2535 CONF_CHANNEL_TYPE_EDCF,
2536 wl1271_tx_get_queue(queue),
2537 ps_scheme, CONF_ACK_POLICY_LEGACY,
2538 0, 0);
2539 if (ret < 0)
2540 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002541
2542out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002543 wl1271_ps_elp_sleep(wl);
2544 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002545
2546out:
2547 mutex_unlock(&wl->mutex);
2548
2549 return ret;
2550}
2551
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002552static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2553{
2554
2555 struct wl1271 *wl = hw->priv;
2556 u64 mactime = ULLONG_MAX;
2557 int ret;
2558
2559 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2560
2561 mutex_lock(&wl->mutex);
2562
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002563 if (unlikely(wl->state == WL1271_STATE_OFF))
2564 goto out;
2565
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002566 ret = wl1271_ps_elp_wakeup(wl, false);
2567 if (ret < 0)
2568 goto out;
2569
2570 ret = wl1271_acx_tsf_info(wl, &mactime);
2571 if (ret < 0)
2572 goto out_sleep;
2573
2574out_sleep:
2575 wl1271_ps_elp_sleep(wl);
2576
2577out:
2578 mutex_unlock(&wl->mutex);
2579 return mactime;
2580}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581
John W. Linvilleece550d2010-07-28 16:41:06 -04002582static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2583 struct survey_info *survey)
2584{
2585 struct wl1271 *wl = hw->priv;
2586 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002587
John W. Linvilleece550d2010-07-28 16:41:06 -04002588 if (idx != 0)
2589 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002590
John W. Linvilleece550d2010-07-28 16:41:06 -04002591 survey->channel = conf->channel;
2592 survey->filled = SURVEY_INFO_NOISE_DBM;
2593 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002594
John W. Linvilleece550d2010-07-28 16:41:06 -04002595 return 0;
2596}
2597
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002598static int wl1271_allocate_hlid(struct wl1271 *wl,
2599 struct ieee80211_sta *sta,
2600 u8 *hlid)
2601{
2602 struct wl1271_station *wl_sta;
2603 int id;
2604
2605 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2606 if (id >= AP_MAX_STATIONS) {
2607 wl1271_warning("could not allocate HLID - too much stations");
2608 return -EBUSY;
2609 }
2610
2611 wl_sta = (struct wl1271_station *)sta->drv_priv;
2612
2613 __set_bit(id, wl->ap_hlid_map);
2614 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2615 *hlid = wl_sta->hlid;
2616 return 0;
2617}
2618
2619static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2620{
2621 int id = hlid - WL1271_AP_STA_HLID_START;
2622
2623 __clear_bit(id, wl->ap_hlid_map);
2624}
2625
2626static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2627 struct ieee80211_vif *vif,
2628 struct ieee80211_sta *sta)
2629{
2630 struct wl1271 *wl = hw->priv;
2631 int ret = 0;
2632 u8 hlid;
2633
2634 mutex_lock(&wl->mutex);
2635
2636 if (unlikely(wl->state == WL1271_STATE_OFF))
2637 goto out;
2638
2639 if (wl->bss_type != BSS_TYPE_AP_BSS)
2640 goto out;
2641
2642 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2643
2644 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2645 if (ret < 0)
2646 goto out;
2647
2648 ret = wl1271_ps_elp_wakeup(wl, false);
2649 if (ret < 0)
2650 goto out;
2651
2652 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2653 if (ret < 0)
2654 goto out_sleep;
2655
2656out_sleep:
2657 wl1271_ps_elp_sleep(wl);
2658
2659out:
2660 mutex_unlock(&wl->mutex);
2661 return ret;
2662}
2663
2664static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2665 struct ieee80211_vif *vif,
2666 struct ieee80211_sta *sta)
2667{
2668 struct wl1271 *wl = hw->priv;
2669 struct wl1271_station *wl_sta;
2670 int ret = 0, id;
2671
2672 mutex_lock(&wl->mutex);
2673
2674 if (unlikely(wl->state == WL1271_STATE_OFF))
2675 goto out;
2676
2677 if (wl->bss_type != BSS_TYPE_AP_BSS)
2678 goto out;
2679
2680 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2681
2682 wl_sta = (struct wl1271_station *)sta->drv_priv;
2683 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2684 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2685 goto out;
2686
2687 ret = wl1271_ps_elp_wakeup(wl, false);
2688 if (ret < 0)
2689 goto out;
2690
2691 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2692 if (ret < 0)
2693 goto out_sleep;
2694
2695 wl1271_free_hlid(wl, wl_sta->hlid);
2696
2697out_sleep:
2698 wl1271_ps_elp_sleep(wl);
2699
2700out:
2701 mutex_unlock(&wl->mutex);
2702 return ret;
2703}
2704
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705/* can't be const, mac80211 writes to this */
2706static struct ieee80211_rate wl1271_rates[] = {
2707 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002708 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2709 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002710 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002711 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2712 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2714 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002715 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2716 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2718 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002719 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2720 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2722 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002723 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2724 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002726 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2727 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002729 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2730 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002732 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2733 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002735 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2736 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002738 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2739 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002741 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2742 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002744 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2745 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002746};
2747
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002748/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002750 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002751 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002752 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2753 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2754 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002755 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002756 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2757 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2758 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002759 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002760 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2761 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2762 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002763};
2764
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002765/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002766static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002767 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002768 7, /* CONF_HW_RXTX_RATE_MCS7 */
2769 6, /* CONF_HW_RXTX_RATE_MCS6 */
2770 5, /* CONF_HW_RXTX_RATE_MCS5 */
2771 4, /* CONF_HW_RXTX_RATE_MCS4 */
2772 3, /* CONF_HW_RXTX_RATE_MCS3 */
2773 2, /* CONF_HW_RXTX_RATE_MCS2 */
2774 1, /* CONF_HW_RXTX_RATE_MCS1 */
2775 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002776
2777 11, /* CONF_HW_RXTX_RATE_54 */
2778 10, /* CONF_HW_RXTX_RATE_48 */
2779 9, /* CONF_HW_RXTX_RATE_36 */
2780 8, /* CONF_HW_RXTX_RATE_24 */
2781
2782 /* TI-specific rate */
2783 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2784
2785 7, /* CONF_HW_RXTX_RATE_18 */
2786 6, /* CONF_HW_RXTX_RATE_12 */
2787 3, /* CONF_HW_RXTX_RATE_11 */
2788 5, /* CONF_HW_RXTX_RATE_9 */
2789 4, /* CONF_HW_RXTX_RATE_6 */
2790 2, /* CONF_HW_RXTX_RATE_5_5 */
2791 1, /* CONF_HW_RXTX_RATE_2 */
2792 0 /* CONF_HW_RXTX_RATE_1 */
2793};
2794
Shahar Levie8b03a22010-10-13 16:09:39 +02002795/* 11n STA capabilities */
2796#define HW_RX_HIGHEST_RATE 72
2797
Shahar Levi00d20102010-11-08 11:20:10 +00002798#ifdef CONFIG_WL12XX_HT
2799#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002800 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2801 .ht_supported = true, \
2802 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2803 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2804 .mcs = { \
2805 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2806 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2807 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2808 }, \
2809}
Shahar Levi18357852010-10-13 16:09:41 +02002810#else
Shahar Levi00d20102010-11-08 11:20:10 +00002811#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002812 .ht_supported = false, \
2813}
2814#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002816/* can't be const, mac80211 writes to this */
2817static struct ieee80211_supported_band wl1271_band_2ghz = {
2818 .channels = wl1271_channels,
2819 .n_channels = ARRAY_SIZE(wl1271_channels),
2820 .bitrates = wl1271_rates,
2821 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002822 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002823};
2824
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002825/* 5 GHz data rates for WL1273 */
2826static struct ieee80211_rate wl1271_rates_5ghz[] = {
2827 { .bitrate = 60,
2828 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2829 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2830 { .bitrate = 90,
2831 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2832 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2833 { .bitrate = 120,
2834 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2835 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2836 { .bitrate = 180,
2837 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2838 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2839 { .bitrate = 240,
2840 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2841 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2842 { .bitrate = 360,
2843 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2844 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2845 { .bitrate = 480,
2846 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2847 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2848 { .bitrate = 540,
2849 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2850 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2851};
2852
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002853/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002854static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002855 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002856 { .hw_value = 8, .center_freq = 5040},
2857 { .hw_value = 9, .center_freq = 5045},
2858 { .hw_value = 11, .center_freq = 5055},
2859 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002860 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002861 { .hw_value = 34, .center_freq = 5170},
2862 { .hw_value = 36, .center_freq = 5180},
2863 { .hw_value = 38, .center_freq = 5190},
2864 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002865 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002866 { .hw_value = 44, .center_freq = 5220},
2867 { .hw_value = 46, .center_freq = 5230},
2868 { .hw_value = 48, .center_freq = 5240},
2869 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002870 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002871 { .hw_value = 60, .center_freq = 5300},
2872 { .hw_value = 64, .center_freq = 5320},
2873 { .hw_value = 100, .center_freq = 5500},
2874 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002875 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002876 { .hw_value = 112, .center_freq = 5560},
2877 { .hw_value = 116, .center_freq = 5580},
2878 { .hw_value = 120, .center_freq = 5600},
2879 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002880 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002881 { .hw_value = 132, .center_freq = 5660},
2882 { .hw_value = 136, .center_freq = 5680},
2883 { .hw_value = 140, .center_freq = 5700},
2884 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002885 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002886 { .hw_value = 157, .center_freq = 5785},
2887 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002888 { .hw_value = 165, .center_freq = 5825},
2889};
2890
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002891/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002892static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002893 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002894 7, /* CONF_HW_RXTX_RATE_MCS7 */
2895 6, /* CONF_HW_RXTX_RATE_MCS6 */
2896 5, /* CONF_HW_RXTX_RATE_MCS5 */
2897 4, /* CONF_HW_RXTX_RATE_MCS4 */
2898 3, /* CONF_HW_RXTX_RATE_MCS3 */
2899 2, /* CONF_HW_RXTX_RATE_MCS2 */
2900 1, /* CONF_HW_RXTX_RATE_MCS1 */
2901 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002902
2903 7, /* CONF_HW_RXTX_RATE_54 */
2904 6, /* CONF_HW_RXTX_RATE_48 */
2905 5, /* CONF_HW_RXTX_RATE_36 */
2906 4, /* CONF_HW_RXTX_RATE_24 */
2907
2908 /* TI-specific rate */
2909 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2910
2911 3, /* CONF_HW_RXTX_RATE_18 */
2912 2, /* CONF_HW_RXTX_RATE_12 */
2913 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2914 1, /* CONF_HW_RXTX_RATE_9 */
2915 0, /* CONF_HW_RXTX_RATE_6 */
2916 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2917 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2918 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2919};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002920
2921static struct ieee80211_supported_band wl1271_band_5ghz = {
2922 .channels = wl1271_channels_5ghz,
2923 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2924 .bitrates = wl1271_rates_5ghz,
2925 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002926 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002927};
2928
Tobias Klausera0ea9492010-05-20 10:38:11 +02002929static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002930 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2931 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2932};
2933
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934static const struct ieee80211_ops wl1271_ops = {
2935 .start = wl1271_op_start,
2936 .stop = wl1271_op_stop,
2937 .add_interface = wl1271_op_add_interface,
2938 .remove_interface = wl1271_op_remove_interface,
2939 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002940 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 .configure_filter = wl1271_op_configure_filter,
2942 .tx = wl1271_op_tx,
2943 .set_key = wl1271_op_set_key,
2944 .hw_scan = wl1271_op_hw_scan,
2945 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002946 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002948 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002949 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002950 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002951 .sta_add = wl1271_op_sta_add,
2952 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002953 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954};
2955
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002956
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002957u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002958{
2959 u8 idx;
2960
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002961 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002962
2963 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2964 wl1271_error("Illegal RX rate from HW: %d", rate);
2965 return 0;
2966 }
2967
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002968 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002969 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2970 wl1271_error("Unsupported RX rate from HW: %d", rate);
2971 return 0;
2972 }
2973
2974 return idx;
2975}
2976
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002977static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2978 struct device_attribute *attr,
2979 char *buf)
2980{
2981 struct wl1271 *wl = dev_get_drvdata(dev);
2982 ssize_t len;
2983
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002984 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002985
2986 mutex_lock(&wl->mutex);
2987 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2988 wl->sg_enabled);
2989 mutex_unlock(&wl->mutex);
2990
2991 return len;
2992
2993}
2994
2995static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2996 struct device_attribute *attr,
2997 const char *buf, size_t count)
2998{
2999 struct wl1271 *wl = dev_get_drvdata(dev);
3000 unsigned long res;
3001 int ret;
3002
3003 ret = strict_strtoul(buf, 10, &res);
3004
3005 if (ret < 0) {
3006 wl1271_warning("incorrect value written to bt_coex_mode");
3007 return count;
3008 }
3009
3010 mutex_lock(&wl->mutex);
3011
3012 res = !!res;
3013
3014 if (res == wl->sg_enabled)
3015 goto out;
3016
3017 wl->sg_enabled = res;
3018
3019 if (wl->state == WL1271_STATE_OFF)
3020 goto out;
3021
3022 ret = wl1271_ps_elp_wakeup(wl, false);
3023 if (ret < 0)
3024 goto out;
3025
3026 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3027 wl1271_ps_elp_sleep(wl);
3028
3029 out:
3030 mutex_unlock(&wl->mutex);
3031 return count;
3032}
3033
3034static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3035 wl1271_sysfs_show_bt_coex_state,
3036 wl1271_sysfs_store_bt_coex_state);
3037
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003038static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3039 struct device_attribute *attr,
3040 char *buf)
3041{
3042 struct wl1271 *wl = dev_get_drvdata(dev);
3043 ssize_t len;
3044
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003045 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003046
3047 mutex_lock(&wl->mutex);
3048 if (wl->hw_pg_ver >= 0)
3049 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3050 else
3051 len = snprintf(buf, len, "n/a\n");
3052 mutex_unlock(&wl->mutex);
3053
3054 return len;
3055}
3056
3057static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3058 wl1271_sysfs_show_hw_pg_ver, NULL);
3059
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003060int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061{
3062 int ret;
3063
3064 if (wl->mac80211_registered)
3065 return 0;
3066
3067 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3068
3069 ret = ieee80211_register_hw(wl->hw);
3070 if (ret < 0) {
3071 wl1271_error("unable to register mac80211 hw: %d", ret);
3072 return ret;
3073 }
3074
3075 wl->mac80211_registered = true;
3076
Eliad Pellerd60080a2010-11-24 12:53:16 +02003077 wl1271_debugfs_init(wl);
3078
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003079 register_netdevice_notifier(&wl1271_dev_notifier);
3080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003081 wl1271_notice("loaded");
3082
3083 return 0;
3084}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003085EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003086
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003087void wl1271_unregister_hw(struct wl1271 *wl)
3088{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003089 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003090 ieee80211_unregister_hw(wl->hw);
3091 wl->mac80211_registered = false;
3092
3093}
3094EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3095
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003096int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003097{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003098 static const u32 cipher_suites[] = {
3099 WLAN_CIPHER_SUITE_WEP40,
3100 WLAN_CIPHER_SUITE_WEP104,
3101 WLAN_CIPHER_SUITE_TKIP,
3102 WLAN_CIPHER_SUITE_CCMP,
3103 WL1271_CIPHER_SUITE_GEM,
3104 };
3105
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003106 /* The tx descriptor buffer and the TKIP space. */
3107 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3108 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109
3110 /* unit us */
3111 /* FIXME: find a proper value */
3112 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003113 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114
3115 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003116 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003117 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003118 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003119 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003120 IEEE80211_HW_CONNECTION_MONITOR |
3121 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003122
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003123 wl->hw->wiphy->cipher_suites = cipher_suites;
3124 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3125
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003126 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3127 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003128 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003129 /*
3130 * Maximum length of elements in scanning probe request templates
3131 * should be the maximum length possible for a template, without
3132 * the IEEE80211 header of the template
3133 */
3134 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3135 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003136 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03003137 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003138
Kalle Valo12bd8942010-03-18 12:26:33 +02003139 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003140 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003141
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003142 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3143
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003144 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003146 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003148 return 0;
3149}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003150EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003151
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003152#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003153
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003154struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003155{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003157 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003158 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003159 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003160 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003161
3162 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3163 if (!hw) {
3164 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003165 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003166 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003167 }
3168
Julia Lawall929ebd32010-05-15 23:16:39 +02003169 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003170 if (!plat_dev) {
3171 wl1271_error("could not allocate platform_device");
3172 ret = -ENOMEM;
3173 goto err_plat_alloc;
3174 }
3175
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003176 wl = hw->priv;
3177 memset(wl, 0, sizeof(*wl));
3178
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003179 INIT_LIST_HEAD(&wl->list);
3180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003181 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003182 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003183
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003184 for (i = 0; i < NUM_TX_QUEUES; i++)
3185 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003186
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003187 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003188 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003189 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3190 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3191 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3192 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003193 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003194 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003195 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003197 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3198 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003199 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003200 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003201 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003202 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003203 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3204 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003205 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003206 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003207 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003208 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003209 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003210 wl->bss_type = MAX_BSS_TYPE;
3211 wl->set_bss_type = MAX_BSS_TYPE;
3212 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003214 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003215 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216 wl->tx_frames[i] = NULL;
3217
3218 spin_lock_init(&wl->wl_lock);
3219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220 wl->state = WL1271_STATE_OFF;
3221 mutex_init(&wl->mutex);
3222
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003223 /* Apply default driver configuration. */
3224 wl1271_conf_init(wl);
3225
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003226 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3227 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3228 if (!wl->aggr_buf) {
3229 ret = -ENOMEM;
3230 goto err_hw;
3231 }
3232
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003233 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003234 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003235 if (ret) {
3236 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003237 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003238 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003239 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003240
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003241 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003242 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003243 if (ret < 0) {
3244 wl1271_error("failed to create sysfs file bt_coex_state");
3245 goto err_platform;
3246 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003247
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003248 /* Create sysfs file to get HW PG version */
3249 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3250 if (ret < 0) {
3251 wl1271_error("failed to create sysfs file hw_pg_ver");
3252 goto err_bt_coex_state;
3253 }
3254
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003255 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003256
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003257err_bt_coex_state:
3258 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3259
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003260err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003261 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003262
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003263err_aggr:
3264 free_pages((unsigned long)wl->aggr_buf, order);
3265
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003266err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003267 wl1271_debugfs_exit(wl);
3268 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003269
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003270err_plat_alloc:
3271 ieee80211_free_hw(hw);
3272
3273err_hw_alloc:
3274
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003275 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003276}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003277EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003278
3279int wl1271_free_hw(struct wl1271 *wl)
3280{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003281 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003282 free_pages((unsigned long)wl->aggr_buf,
3283 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003284 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003285
3286 wl1271_debugfs_exit(wl);
3287
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003288 vfree(wl->fw);
3289 wl->fw = NULL;
3290 kfree(wl->nvs);
3291 wl->nvs = NULL;
3292
3293 kfree(wl->fw_status);
3294 kfree(wl->tx_res_if);
3295
3296 ieee80211_free_hw(wl->hw);
3297
3298 return 0;
3299}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003300EXPORT_SYMBOL_GPL(wl1271_free_hw);
3301
Eliad Peller17c17552010-12-12 12:15:35 +02003302u32 wl12xx_debug_level;
3303EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3304module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3305MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3306
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003307MODULE_LICENSE("GPL");
3308MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3309MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");