blob: 4ca46b2d7f343c23cfd374a9f762e1ad155aa4a3 [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;
661 int ret;
662
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200663 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664
665 if (ret < 0) {
666 wl1271_error("could not get firmware: %d", ret);
667 return ret;
668 }
669
670 if (fw->size % 4) {
671 wl1271_error("firmware size is not multiple of 32 bits: %zu",
672 fw->size);
673 ret = -EILSEQ;
674 goto out;
675 }
676
677 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300678 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679
680 if (!wl->fw) {
681 wl1271_error("could not allocate memory for the firmware");
682 ret = -ENOMEM;
683 goto out;
684 }
685
686 memcpy(wl->fw, fw->data, wl->fw_len);
687
688 ret = 0;
689
690out:
691 release_firmware(fw);
692
693 return ret;
694}
695
696static int wl1271_fetch_nvs(struct wl1271 *wl)
697{
698 const struct firmware *fw;
699 int ret;
700
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200701 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 if (ret < 0) {
704 wl1271_error("could not get nvs file: %d", ret);
705 return ret;
706 }
707
Julia Lawall929ebd32010-05-15 23:16:39 +0200708 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
710 if (!wl->nvs) {
711 wl1271_error("could not allocate memory for the nvs file");
712 ret = -ENOMEM;
713 goto out;
714 }
715
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200716 wl->nvs_len = fw->size;
717
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718out:
719 release_firmware(fw);
720
721 return ret;
722}
723
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200724static void wl1271_recovery_work(struct work_struct *work)
725{
726 struct wl1271 *wl =
727 container_of(work, struct wl1271, recovery_work);
728
729 mutex_lock(&wl->mutex);
730
731 if (wl->state != WL1271_STATE_ON)
732 goto out;
733
734 wl1271_info("Hardware recovery in progress.");
735
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200736 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
737 ieee80211_connection_loss(wl->vif);
738
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200739 /* reboot the chipset */
740 __wl1271_op_remove_interface(wl);
741 ieee80211_restart_hw(wl->hw);
742
743out:
744 mutex_unlock(&wl->mutex);
745}
746
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747static void wl1271_fw_wakeup(struct wl1271 *wl)
748{
749 u32 elp_reg;
750
751 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300752 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300753}
754
755static int wl1271_setup(struct wl1271 *wl)
756{
757 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
758 if (!wl->fw_status)
759 return -ENOMEM;
760
761 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
762 if (!wl->tx_res_if) {
763 kfree(wl->fw_status);
764 return -ENOMEM;
765 }
766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767 return 0;
768}
769
770static int wl1271_chip_wakeup(struct wl1271 *wl)
771{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300772 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773 int ret = 0;
774
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200775 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200776 ret = wl1271_power_on(wl);
777 if (ret < 0)
778 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200780 wl1271_io_reset(wl);
781 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782
783 /* We don't need a real memory partition here, because we only want
784 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300785 memset(&partition, 0, sizeof(partition));
786 partition.reg.start = REGISTERS_BASE;
787 partition.reg.size = REGISTERS_DOWN_SIZE;
788 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790 /* ELP module wake up */
791 wl1271_fw_wakeup(wl);
792
793 /* whal_FwCtrl_BootSm() */
794
795 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200796 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797
798 /* 1. check if chip id is valid */
799
800 switch (wl->chip.id) {
801 case CHIP_ID_1271_PG10:
802 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
803 wl->chip.id);
804
805 ret = wl1271_setup(wl);
806 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200807 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 break;
809 case CHIP_ID_1271_PG20:
810 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
811 wl->chip.id);
812
813 ret = wl1271_setup(wl);
814 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200815 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 break;
817 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200818 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200820 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821 }
822
823 if (wl->fw == NULL) {
824 ret = wl1271_fetch_firmware(wl);
825 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200826 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827 }
828
829 /* No NVS from netlink, try to get it from the filesystem */
830 if (wl->nvs == NULL) {
831 ret = wl1271_fetch_nvs(wl);
832 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200833 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 }
835
836out:
837 return ret;
838}
839
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840int wl1271_plt_start(struct wl1271 *wl)
841{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200842 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 int ret;
844
845 mutex_lock(&wl->mutex);
846
847 wl1271_notice("power up");
848
849 if (wl->state != WL1271_STATE_OFF) {
850 wl1271_error("cannot go into PLT state because not "
851 "in off state: %d", wl->state);
852 ret = -EBUSY;
853 goto out;
854 }
855
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200856 while (retries) {
857 retries--;
858 ret = wl1271_chip_wakeup(wl);
859 if (ret < 0)
860 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200862 ret = wl1271_boot(wl);
863 if (ret < 0)
864 goto power_off;
865
866 ret = wl1271_plt_init(wl);
867 if (ret < 0)
868 goto irq_disable;
869
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200870 wl->state = WL1271_STATE_PLT;
871 wl1271_notice("firmware booted in PLT mode (%s)",
872 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873 goto out;
874
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200875irq_disable:
876 wl1271_disable_interrupts(wl);
877 mutex_unlock(&wl->mutex);
878 /* Unlocking the mutex in the middle of handling is
879 inherently unsafe. In this case we deem it safe to do,
880 because we need to let any possibly pending IRQ out of
881 the system (and while we are WL1271_STATE_OFF the IRQ
882 work function will not do anything.) Also, any other
883 possible concurrent operations will fail due to the
884 current state, hence the wl1271 struct should be safe. */
885 cancel_work_sync(&wl->irq_work);
886 mutex_lock(&wl->mutex);
887power_off:
888 wl1271_power_off(wl);
889 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200891 wl1271_error("firmware boot in PLT mode failed despite %d retries",
892 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893out:
894 mutex_unlock(&wl->mutex);
895
896 return ret;
897}
898
899int wl1271_plt_stop(struct wl1271 *wl)
900{
901 int ret = 0;
902
903 mutex_lock(&wl->mutex);
904
905 wl1271_notice("power down");
906
907 if (wl->state != WL1271_STATE_PLT) {
908 wl1271_error("cannot power down because not in PLT "
909 "state: %d", wl->state);
910 ret = -EBUSY;
911 goto out;
912 }
913
914 wl1271_disable_interrupts(wl);
915 wl1271_power_off(wl);
916
917 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300918 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919
920out:
921 mutex_unlock(&wl->mutex);
922
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200923 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200924 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 return ret;
927}
928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
930{
931 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200932 struct ieee80211_conf *conf = &hw->conf;
933 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
934 struct ieee80211_sta *sta = txinfo->control.sta;
935 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200936 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
Shahar Levi18357852010-10-13 16:09:41 +0200938 /*
939 * peek into the rates configured in the STA entry.
940 * The rates set after connection stage, The first block only BG sets:
941 * the compare is for bit 0-16 of sta_rate_set. The second block add
942 * HT rates in case of HT supported.
943 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200944 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200945 if (sta &&
946 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200947 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
948 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200949 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
950 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
951 }
Shahar Levi18357852010-10-13 16:09:41 +0200952
Shahar Levi00d20102010-11-08 11:20:10 +0000953#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200954 if (sta &&
955 sta->ht_cap.ht_supported &&
956 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
957 sta->ht_cap.mcs.rx_mask[0])) {
958 /* Clean MCS bits before setting them */
959 wl->sta_rate_set &= HW_BG_RATES_MASK;
960 wl->sta_rate_set |=
961 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
962 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
963 }
964#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200965 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200966 spin_unlock_irqrestore(&wl->wl_lock, flags);
967
968 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200969 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
970 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971
972 /*
973 * The chip specific setup must run before the first TX packet -
974 * before that, the tx_work will not be initialized!
975 */
976
Ido Yariva5225502010-10-12 14:49:10 +0200977 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
978 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
980 /*
981 * The workqueue is slow to process the tx_queue and we need stop
982 * the queue here, otherwise the queue will get too long.
983 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200984 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200985 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200987 spin_lock_irqsave(&wl->wl_lock, flags);
988 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200989 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200990 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 }
992
993 return NETDEV_TX_OK;
994}
995
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300996static struct notifier_block wl1271_dev_notifier = {
997 .notifier_call = wl1271_dev_notify,
998};
999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000static int wl1271_op_start(struct ieee80211_hw *hw)
1001{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001002 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1003
1004 /*
1005 * We have to delay the booting of the hardware because
1006 * we need to know the local MAC address before downloading and
1007 * initializing the firmware. The MAC address cannot be changed
1008 * after boot, and without the proper MAC address, the firmware
1009 * will not function properly.
1010 *
1011 * The MAC address is first known when the corresponding interface
1012 * is added. That is where we will initialize the hardware.
1013 */
1014
1015 return 0;
1016}
1017
1018static void wl1271_op_stop(struct ieee80211_hw *hw)
1019{
1020 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1021}
1022
1023static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1024 struct ieee80211_vif *vif)
1025{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001027 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001028 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001030 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001032 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1033 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
1035 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001036 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001037 wl1271_debug(DEBUG_MAC80211,
1038 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001039 ret = -EBUSY;
1040 goto out;
1041 }
1042
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001043 switch (vif->type) {
1044 case NL80211_IFTYPE_STATION:
1045 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001046 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001047 break;
1048 case NL80211_IFTYPE_ADHOC:
1049 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001050 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001051 break;
1052 default:
1053 ret = -EOPNOTSUPP;
1054 goto out;
1055 }
1056
1057 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
1059 if (wl->state != WL1271_STATE_OFF) {
1060 wl1271_error("cannot start because not in off state: %d",
1061 wl->state);
1062 ret = -EBUSY;
1063 goto out;
1064 }
1065
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001066 while (retries) {
1067 retries--;
1068 ret = wl1271_chip_wakeup(wl);
1069 if (ret < 0)
1070 goto power_off;
1071
1072 ret = wl1271_boot(wl);
1073 if (ret < 0)
1074 goto power_off;
1075
1076 ret = wl1271_hw_init(wl);
1077 if (ret < 0)
1078 goto irq_disable;
1079
Eliad Peller71125ab2010-10-28 21:46:43 +02001080 booted = true;
1081 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001083irq_disable:
1084 wl1271_disable_interrupts(wl);
1085 mutex_unlock(&wl->mutex);
1086 /* Unlocking the mutex in the middle of handling is
1087 inherently unsafe. In this case we deem it safe to do,
1088 because we need to let any possibly pending IRQ out of
1089 the system (and while we are WL1271_STATE_OFF the IRQ
1090 work function will not do anything.) Also, any other
1091 possible concurrent operations will fail due to the
1092 current state, hence the wl1271 struct should be safe. */
1093 cancel_work_sync(&wl->irq_work);
1094 mutex_lock(&wl->mutex);
1095power_off:
1096 wl1271_power_off(wl);
1097 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098
Eliad Peller71125ab2010-10-28 21:46:43 +02001099 if (!booted) {
1100 wl1271_error("firmware boot failed despite %d retries",
1101 WL1271_BOOT_RETRIES);
1102 goto out;
1103 }
1104
1105 wl->vif = vif;
1106 wl->state = WL1271_STATE_ON;
1107 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1108
1109 /* update hw/fw version info in wiphy struct */
1110 wiphy->hw_version = wl->chip.id;
1111 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1112 sizeof(wiphy->fw_version));
1113
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001114 /*
1115 * Now we know if 11a is supported (info from the NVS), so disable
1116 * 11a channels if not supported
1117 */
1118 if (!wl->enable_11a)
1119 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1120
1121 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1122 wl->enable_11a ? "" : "not ");
1123
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001124out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125 mutex_unlock(&wl->mutex);
1126
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001127 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001128 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001129
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130 return ret;
1131}
1132
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001133static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135 int i;
1136
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001137 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001139 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001141 list_del(&wl->list);
1142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143 WARN_ON(wl->state != WL1271_STATE_ON);
1144
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001145 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001146 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001147 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001148
Luciano Coelho08688d62010-07-08 17:50:07 +03001149 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001150 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1151 kfree(wl->scan.scanned_ch);
1152 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001153 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001154 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001155 }
1156
1157 wl->state = WL1271_STATE_OFF;
1158
1159 wl1271_disable_interrupts(wl);
1160
1161 mutex_unlock(&wl->mutex);
1162
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001163 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164 cancel_work_sync(&wl->irq_work);
1165 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001166 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001167 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168
1169 mutex_lock(&wl->mutex);
1170
1171 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001172 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173 wl1271_power_off(wl);
1174
1175 memset(wl->bssid, 0, ETH_ALEN);
1176 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1177 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001179 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001180 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181
1182 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001183 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001184 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1185 wl->tx_blocks_available = 0;
1186 wl->tx_results_count = 0;
1187 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001188 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001189 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001190 wl->time_offset = 0;
1191 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001192 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1193 wl->sta_rate_set = 0;
1194 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001195 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001196 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001197 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001198 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200 for (i = 0; i < NUM_TX_QUEUES; i++)
1201 wl->tx_blocks_freed[i] = 0;
1202
1203 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001204
1205 kfree(wl->fw_status);
1206 wl->fw_status = NULL;
1207 kfree(wl->tx_res_if);
1208 wl->tx_res_if = NULL;
1209 kfree(wl->target_mem_map);
1210 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001211}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001212
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001213static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1214 struct ieee80211_vif *vif)
1215{
1216 struct wl1271 *wl = hw->priv;
1217
1218 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001219 /*
1220 * wl->vif can be null here if someone shuts down the interface
1221 * just when hardware recovery has been started.
1222 */
1223 if (wl->vif) {
1224 WARN_ON(wl->vif != vif);
1225 __wl1271_op_remove_interface(wl);
1226 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001227
Juuso Oikarinen67353292010-11-18 15:19:02 +02001228 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001229 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230}
1231
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001232static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1233{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001234 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001235
1236 /* combine requested filters with current filter config */
1237 filters = wl->filters | filters;
1238
1239 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1240
1241 if (filters & FIF_PROMISC_IN_BSS) {
1242 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1243 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1244 wl->rx_config |= CFG_BSSID_FILTER_EN;
1245 }
1246 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1247 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1248 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1249 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1250 }
1251 if (filters & FIF_OTHER_BSS) {
1252 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1253 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1254 }
1255 if (filters & FIF_CONTROL) {
1256 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1257 wl->rx_filter |= CFG_RX_CTL_EN;
1258 }
1259 if (filters & FIF_FCSFAIL) {
1260 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1261 wl->rx_filter |= CFG_RX_FCS_ERROR;
1262 }
1263}
1264
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001265static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001266{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001267 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001268 /* we need to use a dummy BSSID for now */
1269 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1270 0xad, 0xbe, 0xef };
1271
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001272 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1273
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001274 /* pass through frames from all BSS */
1275 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1276
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001277 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001278 if (ret < 0)
1279 goto out;
1280
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001281 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001282
1283out:
1284 return ret;
1285}
1286
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001287static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001288{
1289 int ret;
1290
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001291 /*
1292 * One of the side effects of the JOIN command is that is clears
1293 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1294 * to a WPA/WPA2 access point will therefore kill the data-path.
1295 * Currently there is no supported scenario for JOIN during
1296 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1297 * must be handled somehow.
1298 *
1299 */
1300 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1301 wl1271_info("JOIN while associated.");
1302
1303 if (set_assoc)
1304 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1305
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001306 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1307 if (ret < 0)
1308 goto out;
1309
1310 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1311
1312 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1313 goto out;
1314
1315 /*
1316 * The join command disable the keep-alive mode, shut down its process,
1317 * and also clear the template config, so we need to reset it all after
1318 * the join. The acx_aid starts the keep-alive process, and the order
1319 * of the commands below is relevant.
1320 */
1321 ret = wl1271_acx_keep_alive_mode(wl, true);
1322 if (ret < 0)
1323 goto out;
1324
1325 ret = wl1271_acx_aid(wl, wl->aid);
1326 if (ret < 0)
1327 goto out;
1328
1329 ret = wl1271_cmd_build_klv_null_data(wl);
1330 if (ret < 0)
1331 goto out;
1332
1333 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1334 ACX_KEEP_ALIVE_TPL_VALID);
1335 if (ret < 0)
1336 goto out;
1337
1338out:
1339 return ret;
1340}
1341
1342static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001343{
1344 int ret;
1345
1346 /* to stop listening to a channel, we disconnect */
1347 ret = wl1271_cmd_disconnect(wl);
1348 if (ret < 0)
1349 goto out;
1350
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001351 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001352 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001353
1354 /* stop filterting packets based on bssid */
1355 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001356
1357out:
1358 return ret;
1359}
1360
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001361static void wl1271_set_band_rate(struct wl1271 *wl)
1362{
1363 if (wl->band == IEEE80211_BAND_2GHZ)
1364 wl->basic_rate_set = wl->conf.tx.basic_rate;
1365 else
1366 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1367}
1368
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001369static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001370{
1371 int ret;
1372
1373 if (idle) {
1374 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1375 ret = wl1271_unjoin(wl);
1376 if (ret < 0)
1377 goto out;
1378 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001379 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001380 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001381 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001382 if (ret < 0)
1383 goto out;
1384 ret = wl1271_acx_keep_alive_config(
1385 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1386 ACX_KEEP_ALIVE_TPL_INVALID);
1387 if (ret < 0)
1388 goto out;
1389 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1390 } else {
1391 /* increment the session counter */
1392 wl->session_counter++;
1393 if (wl->session_counter >= SESSION_COUNTER_MAX)
1394 wl->session_counter = 0;
1395 ret = wl1271_dummy_join(wl);
1396 if (ret < 0)
1397 goto out;
1398 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1399 }
1400
1401out:
1402 return ret;
1403}
1404
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1406{
1407 struct wl1271 *wl = hw->priv;
1408 struct ieee80211_conf *conf = &hw->conf;
1409 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001410 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
1412 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1413
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001414 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1415 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001416 channel,
1417 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001418 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001419 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1420 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001422 /*
1423 * mac80211 will go to idle nearly immediately after transmitting some
1424 * frames, such as the deauth. To make sure those frames reach the air,
1425 * wait here until the TX queue is fully flushed.
1426 */
1427 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1428 (conf->flags & IEEE80211_CONF_IDLE))
1429 wl1271_tx_flush(wl);
1430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 mutex_lock(&wl->mutex);
1432
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001433 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1434 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001435 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001436 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001437
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001438 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 ret = wl1271_ps_elp_wakeup(wl, false);
1441 if (ret < 0)
1442 goto out;
1443
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001444 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001445 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1446 ((wl->band != conf->channel->band) ||
1447 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001448 wl->band = conf->channel->band;
1449 wl->channel = channel;
1450
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001451 if (!is_ap) {
1452 /*
1453 * FIXME: the mac80211 should really provide a fixed
1454 * rate to use here. for now, just use the smallest
1455 * possible rate for the band as a fixed rate for
1456 * association frames and other control messages.
1457 */
1458 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1459 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001460
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001461 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1462 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001463 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001464 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001465 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001466
1467 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1468 ret = wl1271_join(wl, false);
1469 if (ret < 0)
1470 wl1271_warning("cmd join on channel "
1471 "failed %d", ret);
1472 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001473 }
1474 }
1475
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001476 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1477 ret = wl1271_sta_handle_idle(wl,
1478 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001479 if (ret < 0)
1480 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481 }
1482
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001483 /*
1484 * if mac80211 changes the PSM mode, make sure the mode is not
1485 * incorrectly changed after the pspoll failure active window.
1486 */
1487 if (changed & IEEE80211_CONF_CHANGE_PS)
1488 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1489
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001490 if (conf->flags & IEEE80211_CONF_PS &&
1491 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1492 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493
1494 /*
1495 * We enter PSM only if we're already associated.
1496 * If we're not, we'll enter it when joining an SSID,
1497 * through the bss_info_changed() hook.
1498 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001499 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001500 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001501 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001502 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001503 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001505 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001506 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001508 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001510 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001511 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001512 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001513 }
1514
1515 if (conf->power_level != wl->power_level) {
1516 ret = wl1271_acx_tx_power(wl, conf->power_level);
1517 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001518 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
1520 wl->power_level = conf->power_level;
1521 }
1522
1523out_sleep:
1524 wl1271_ps_elp_sleep(wl);
1525
1526out:
1527 mutex_unlock(&wl->mutex);
1528
1529 return ret;
1530}
1531
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001532struct wl1271_filter_params {
1533 bool enabled;
1534 int mc_list_length;
1535 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1536};
1537
Jiri Pirko22bedad2010-04-01 21:22:57 +00001538static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1539 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001540{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001541 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001542 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001543 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001544
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001545 if (unlikely(wl->state == WL1271_STATE_OFF))
1546 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001547
Juuso Oikarinen74441132009-10-13 12:47:53 +03001548 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001549 if (!fp) {
1550 wl1271_error("Out of memory setting filters.");
1551 return 0;
1552 }
1553
1554 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001555 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001556 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1557 fp->enabled = false;
1558 } else {
1559 fp->enabled = true;
1560 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001561 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001562 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001563 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001564 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001565 }
1566
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001567 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001570#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1571 FIF_ALLMULTI | \
1572 FIF_FCSFAIL | \
1573 FIF_BCN_PRBRESP_PROMISC | \
1574 FIF_CONTROL | \
1575 FIF_OTHER_BSS)
1576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1578 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001579 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001581 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001583 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584
Arik Nemtsov7d057862010-10-16 19:25:35 +02001585 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1586 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001588 mutex_lock(&wl->mutex);
1589
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001590 *total &= WL1271_SUPPORTED_FILTERS;
1591 changed &= WL1271_SUPPORTED_FILTERS;
1592
1593 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001594 goto out;
1595
1596 ret = wl1271_ps_elp_wakeup(wl, false);
1597 if (ret < 0)
1598 goto out;
1599
Arik Nemtsov7d057862010-10-16 19:25:35 +02001600 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1601 if (*total & FIF_ALLMULTI)
1602 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1603 else if (fp)
1604 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1605 fp->mc_list,
1606 fp->mc_list_length);
1607 if (ret < 0)
1608 goto out_sleep;
1609 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001611 /* determine, whether supported filter values have changed */
1612 if (changed == 0)
1613 goto out_sleep;
1614
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001615 /* configure filters */
1616 wl->filters = *total;
1617 wl1271_configure_filters(wl, 0);
1618
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001619 /* apply configured filters */
1620 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1621 if (ret < 0)
1622 goto out_sleep;
1623
1624out_sleep:
1625 wl1271_ps_elp_sleep(wl);
1626
1627out:
1628 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001629 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001630}
1631
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001632static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1633 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1634 u16 tx_seq_16)
1635{
1636 struct wl1271_ap_key *ap_key;
1637 int i;
1638
1639 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1640
1641 if (key_size > MAX_KEY_SIZE)
1642 return -EINVAL;
1643
1644 /*
1645 * Find next free entry in ap_keys. Also check we are not replacing
1646 * an existing key.
1647 */
1648 for (i = 0; i < MAX_NUM_KEYS; i++) {
1649 if (wl->recorded_ap_keys[i] == NULL)
1650 break;
1651
1652 if (wl->recorded_ap_keys[i]->id == id) {
1653 wl1271_warning("trying to record key replacement");
1654 return -EINVAL;
1655 }
1656 }
1657
1658 if (i == MAX_NUM_KEYS)
1659 return -EBUSY;
1660
1661 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1662 if (!ap_key)
1663 return -ENOMEM;
1664
1665 ap_key->id = id;
1666 ap_key->key_type = key_type;
1667 ap_key->key_size = key_size;
1668 memcpy(ap_key->key, key, key_size);
1669 ap_key->hlid = hlid;
1670 ap_key->tx_seq_32 = tx_seq_32;
1671 ap_key->tx_seq_16 = tx_seq_16;
1672
1673 wl->recorded_ap_keys[i] = ap_key;
1674 return 0;
1675}
1676
1677static void wl1271_free_ap_keys(struct wl1271 *wl)
1678{
1679 int i;
1680
1681 for (i = 0; i < MAX_NUM_KEYS; i++) {
1682 kfree(wl->recorded_ap_keys[i]);
1683 wl->recorded_ap_keys[i] = NULL;
1684 }
1685}
1686
1687static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1688{
1689 int i, ret = 0;
1690 struct wl1271_ap_key *key;
1691 bool wep_key_added = false;
1692
1693 for (i = 0; i < MAX_NUM_KEYS; i++) {
1694 if (wl->recorded_ap_keys[i] == NULL)
1695 break;
1696
1697 key = wl->recorded_ap_keys[i];
1698 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1699 key->id, key->key_type,
1700 key->key_size, key->key,
1701 key->hlid, key->tx_seq_32,
1702 key->tx_seq_16);
1703 if (ret < 0)
1704 goto out;
1705
1706 if (key->key_type == KEY_WEP)
1707 wep_key_added = true;
1708 }
1709
1710 if (wep_key_added) {
1711 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1712 if (ret < 0)
1713 goto out;
1714 }
1715
1716out:
1717 wl1271_free_ap_keys(wl);
1718 return ret;
1719}
1720
1721static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1722 u8 key_size, const u8 *key, u32 tx_seq_32,
1723 u16 tx_seq_16, struct ieee80211_sta *sta)
1724{
1725 int ret;
1726 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1727
1728 if (is_ap) {
1729 struct wl1271_station *wl_sta;
1730 u8 hlid;
1731
1732 if (sta) {
1733 wl_sta = (struct wl1271_station *)sta->drv_priv;
1734 hlid = wl_sta->hlid;
1735 } else {
1736 hlid = WL1271_AP_BROADCAST_HLID;
1737 }
1738
1739 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1740 /*
1741 * We do not support removing keys after AP shutdown.
1742 * Pretend we do to make mac80211 happy.
1743 */
1744 if (action != KEY_ADD_OR_REPLACE)
1745 return 0;
1746
1747 ret = wl1271_record_ap_key(wl, id,
1748 key_type, key_size,
1749 key, hlid, tx_seq_32,
1750 tx_seq_16);
1751 } else {
1752 ret = wl1271_cmd_set_ap_key(wl, action,
1753 id, key_type, key_size,
1754 key, hlid, tx_seq_32,
1755 tx_seq_16);
1756 }
1757
1758 if (ret < 0)
1759 return ret;
1760 } else {
1761 const u8 *addr;
1762 static const u8 bcast_addr[ETH_ALEN] = {
1763 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1764 };
1765
1766 addr = sta ? sta->addr : bcast_addr;
1767
1768 if (is_zero_ether_addr(addr)) {
1769 /* We dont support TX only encryption */
1770 return -EOPNOTSUPP;
1771 }
1772
1773 /* The wl1271 does not allow to remove unicast keys - they
1774 will be cleared automatically on next CMD_JOIN. Ignore the
1775 request silently, as we dont want the mac80211 to emit
1776 an error message. */
1777 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1778 return 0;
1779
1780 ret = wl1271_cmd_set_sta_key(wl, action,
1781 id, key_type, key_size,
1782 key, addr, tx_seq_32,
1783 tx_seq_16);
1784 if (ret < 0)
1785 return ret;
1786
1787 /* the default WEP key needs to be configured at least once */
1788 if (key_type == KEY_WEP) {
1789 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1790 wl->default_key);
1791 if (ret < 0)
1792 return ret;
1793 }
1794 }
1795
1796 return 0;
1797}
1798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1800 struct ieee80211_vif *vif,
1801 struct ieee80211_sta *sta,
1802 struct ieee80211_key_conf *key_conf)
1803{
1804 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001806 u32 tx_seq_32 = 0;
1807 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 u8 key_type;
1809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1811
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001812 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001814 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815 key_conf->keylen, key_conf->flags);
1816 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1817
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 mutex_lock(&wl->mutex);
1819
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001820 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1821 ret = -EAGAIN;
1822 goto out_unlock;
1823 }
1824
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 ret = wl1271_ps_elp_wakeup(wl, false);
1826 if (ret < 0)
1827 goto out_unlock;
1828
Johannes Berg97359d12010-08-10 09:46:38 +02001829 switch (key_conf->cipher) {
1830 case WLAN_CIPHER_SUITE_WEP40:
1831 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 key_type = KEY_WEP;
1833
1834 key_conf->hw_key_idx = key_conf->keyidx;
1835 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001836 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 key_type = KEY_TKIP;
1838
1839 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001840 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1841 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001843 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 key_type = KEY_AES;
1845
1846 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001847 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1848 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001850 case WL1271_CIPHER_SUITE_GEM:
1851 key_type = KEY_GEM;
1852 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1853 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1854 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001856 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857
1858 ret = -EOPNOTSUPP;
1859 goto out_sleep;
1860 }
1861
1862 switch (cmd) {
1863 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001864 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1865 key_conf->keyidx, key_type,
1866 key_conf->keylen, key_conf->key,
1867 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 if (ret < 0) {
1869 wl1271_error("Could not add or replace key");
1870 goto out_sleep;
1871 }
1872 break;
1873
1874 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001875 ret = wl1271_set_key(wl, KEY_REMOVE,
1876 key_conf->keyidx, key_type,
1877 key_conf->keylen, key_conf->key,
1878 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001879 if (ret < 0) {
1880 wl1271_error("Could not remove key");
1881 goto out_sleep;
1882 }
1883 break;
1884
1885 default:
1886 wl1271_error("Unsupported key cmd 0x%x", cmd);
1887 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888 break;
1889 }
1890
1891out_sleep:
1892 wl1271_ps_elp_sleep(wl);
1893
1894out_unlock:
1895 mutex_unlock(&wl->mutex);
1896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897 return ret;
1898}
1899
1900static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001901 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902 struct cfg80211_scan_request *req)
1903{
1904 struct wl1271 *wl = hw->priv;
1905 int ret;
1906 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001907 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908
1909 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1910
1911 if (req->n_ssids) {
1912 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001913 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914 }
1915
1916 mutex_lock(&wl->mutex);
1917
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001918 if (wl->state == WL1271_STATE_OFF) {
1919 /*
1920 * We cannot return -EBUSY here because cfg80211 will expect
1921 * a call to ieee80211_scan_completed if we do - in this case
1922 * there won't be any call.
1923 */
1924 ret = -EAGAIN;
1925 goto out;
1926 }
1927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 ret = wl1271_ps_elp_wakeup(wl, false);
1929 if (ret < 0)
1930 goto out;
1931
Luciano Coelho5924f892010-08-04 03:46:22 +03001932 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001933
1934 wl1271_ps_elp_sleep(wl);
1935
1936out:
1937 mutex_unlock(&wl->mutex);
1938
1939 return ret;
1940}
1941
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001942static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1943{
1944 struct wl1271 *wl = hw->priv;
1945 int ret = 0;
1946
1947 mutex_lock(&wl->mutex);
1948
1949 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1950 ret = -EAGAIN;
1951 goto out;
1952 }
1953
1954 ret = wl1271_ps_elp_wakeup(wl, false);
1955 if (ret < 0)
1956 goto out;
1957
1958 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1959 if (ret < 0)
1960 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1961
1962 wl1271_ps_elp_sleep(wl);
1963
1964out:
1965 mutex_unlock(&wl->mutex);
1966
1967 return ret;
1968}
1969
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1971{
1972 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001973 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974
1975 mutex_lock(&wl->mutex);
1976
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001977 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1978 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001979 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001980 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982 ret = wl1271_ps_elp_wakeup(wl, false);
1983 if (ret < 0)
1984 goto out;
1985
1986 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1987 if (ret < 0)
1988 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1989
1990 wl1271_ps_elp_sleep(wl);
1991
1992out:
1993 mutex_unlock(&wl->mutex);
1994
1995 return ret;
1996}
1997
Arik Nemtsove78a2872010-10-16 19:07:21 +02001998static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02001999 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002000{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002001 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002002
2003 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002004 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002005 if (ptr[0] == WLAN_EID_SSID) {
2006 wl->ssid_len = ptr[1];
2007 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002008 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002009 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002010 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002011 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002012
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002013 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002014 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002015}
2016
Arik Nemtsove78a2872010-10-16 19:07:21 +02002017static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2018 struct ieee80211_bss_conf *bss_conf,
2019 u32 changed)
2020{
2021 int ret = 0;
2022
2023 if (changed & BSS_CHANGED_ERP_SLOT) {
2024 if (bss_conf->use_short_slot)
2025 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2026 else
2027 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2028 if (ret < 0) {
2029 wl1271_warning("Set slot time failed %d", ret);
2030 goto out;
2031 }
2032 }
2033
2034 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2035 if (bss_conf->use_short_preamble)
2036 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2037 else
2038 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2039 }
2040
2041 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2042 if (bss_conf->use_cts_prot)
2043 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2044 else
2045 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2046 if (ret < 0) {
2047 wl1271_warning("Set ctsprotect failed %d", ret);
2048 goto out;
2049 }
2050 }
2051
2052out:
2053 return ret;
2054}
2055
2056static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2057 struct ieee80211_vif *vif,
2058 struct ieee80211_bss_conf *bss_conf,
2059 u32 changed)
2060{
2061 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2062 int ret = 0;
2063
2064 if ((changed & BSS_CHANGED_BEACON_INT)) {
2065 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2066 bss_conf->beacon_int);
2067
2068 wl->beacon_int = bss_conf->beacon_int;
2069 }
2070
2071 if ((changed & BSS_CHANGED_BEACON)) {
2072 struct ieee80211_hdr *hdr;
2073 int ieoffset = offsetof(struct ieee80211_mgmt,
2074 u.beacon.variable);
2075 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2076 u16 tmpl_id;
2077
2078 if (!beacon)
2079 goto out;
2080
2081 wl1271_debug(DEBUG_MASTER, "beacon updated");
2082
2083 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2084 if (ret < 0) {
2085 dev_kfree_skb(beacon);
2086 goto out;
2087 }
2088 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2089 CMD_TEMPL_BEACON;
2090 ret = wl1271_cmd_template_set(wl, tmpl_id,
2091 beacon->data,
2092 beacon->len, 0,
2093 wl1271_tx_min_rate_get(wl));
2094 if (ret < 0) {
2095 dev_kfree_skb(beacon);
2096 goto out;
2097 }
2098
2099 hdr = (struct ieee80211_hdr *) beacon->data;
2100 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2101 IEEE80211_STYPE_PROBE_RESP);
2102
2103 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2104 CMD_TEMPL_PROBE_RESPONSE;
2105 ret = wl1271_cmd_template_set(wl,
2106 tmpl_id,
2107 beacon->data,
2108 beacon->len, 0,
2109 wl1271_tx_min_rate_get(wl));
2110 dev_kfree_skb(beacon);
2111 if (ret < 0)
2112 goto out;
2113 }
2114
2115out:
2116 return ret;
2117}
2118
2119/* AP mode changes */
2120static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121 struct ieee80211_vif *vif,
2122 struct ieee80211_bss_conf *bss_conf,
2123 u32 changed)
2124{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002125 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002126
Arik Nemtsove78a2872010-10-16 19:07:21 +02002127 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2128 u32 rates = bss_conf->basic_rates;
2129 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130
Arik Nemtsove78a2872010-10-16 19:07:21 +02002131 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2132 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2133 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2134 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135
Arik Nemtsove78a2872010-10-16 19:07:21 +02002136 /* update the AP management rate policy with the new rates */
2137 mgmt_rc.enabled_rates = wl->basic_rate_set;
2138 mgmt_rc.long_retry_limit = 10;
2139 mgmt_rc.short_retry_limit = 10;
2140 mgmt_rc.aflags = 0;
2141 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2142 ACX_TX_AP_MODE_MGMT_RATE);
2143 if (ret < 0) {
2144 wl1271_error("AP mgmt policy change failed %d", ret);
2145 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002146 }
2147 }
2148
Arik Nemtsove78a2872010-10-16 19:07:21 +02002149 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2150 if (ret < 0)
2151 goto out;
2152
2153 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2154 if (bss_conf->enable_beacon) {
2155 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2156 ret = wl1271_cmd_start_bss(wl);
2157 if (ret < 0)
2158 goto out;
2159
2160 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2161 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002162
2163 ret = wl1271_ap_init_hwenc(wl);
2164 if (ret < 0)
2165 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002166 }
2167 } else {
2168 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2169 ret = wl1271_cmd_stop_bss(wl);
2170 if (ret < 0)
2171 goto out;
2172
2173 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2174 wl1271_debug(DEBUG_AP, "stopped AP");
2175 }
2176 }
2177 }
2178
2179 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2180 if (ret < 0)
2181 goto out;
2182out:
2183 return;
2184}
2185
2186/* STA/IBSS mode changes */
2187static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2188 struct ieee80211_vif *vif,
2189 struct ieee80211_bss_conf *bss_conf,
2190 u32 changed)
2191{
2192 bool do_join = false, set_assoc = false;
2193 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2194 int ret;
2195 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2196
2197 if (is_ibss) {
2198 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2199 changed);
2200 if (ret < 0)
2201 goto out;
2202 }
2203
2204 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2205 do_join = true;
2206
2207 /* Need to update the SSID (for filtering etc) */
2208 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2209 do_join = true;
2210
2211 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002212 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2213 bss_conf->enable_beacon ? "enabled" : "disabled");
2214
2215 if (bss_conf->enable_beacon)
2216 wl->set_bss_type = BSS_TYPE_IBSS;
2217 else
2218 wl->set_bss_type = BSS_TYPE_STA_BSS;
2219 do_join = true;
2220 }
2221
Arik Nemtsove78a2872010-10-16 19:07:21 +02002222 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002223 bool enable = false;
2224 if (bss_conf->cqm_rssi_thold)
2225 enable = true;
2226 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2227 bss_conf->cqm_rssi_thold,
2228 bss_conf->cqm_rssi_hyst);
2229 if (ret < 0)
2230 goto out;
2231 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2232 }
2233
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002234 if ((changed & BSS_CHANGED_BSSID) &&
2235 /*
2236 * Now we know the correct bssid, so we send a new join command
2237 * and enable the BSSID filter
2238 */
2239 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002240 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002241
Arik Nemtsove78a2872010-10-16 19:07:21 +02002242 ret = wl1271_cmd_build_null_data(wl);
2243 if (ret < 0)
2244 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002245
Arik Nemtsove78a2872010-10-16 19:07:21 +02002246 ret = wl1271_build_qos_null_data(wl);
2247 if (ret < 0)
2248 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002249
Arik Nemtsove78a2872010-10-16 19:07:21 +02002250 /* filter out all packets not from this BSSID */
2251 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002252
Arik Nemtsove78a2872010-10-16 19:07:21 +02002253 /* Need to update the BSSID (for filtering etc) */
2254 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002255 }
2256
Arik Nemtsove78a2872010-10-16 19:07:21 +02002257 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002259 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002260 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002262 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002263
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002264 wl->ps_poll_failures = 0;
2265
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002266 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002267 * use basic rates from AP, and determine lowest rate
2268 * to use with control frames.
2269 */
2270 rates = bss_conf->basic_rates;
2271 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2272 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002273 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002274 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002275 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002276 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002277
2278 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002279 * with wl1271, we don't need to update the
2280 * beacon_int and dtim_period, because the firmware
2281 * updates it by itself when the first beacon is
2282 * received after a join.
2283 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2285 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002286 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002288 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002289 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002290 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002291 dev_kfree_skb(wl->probereq);
2292 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2293 ieoffset = offsetof(struct ieee80211_mgmt,
2294 u.probe_req.variable);
2295 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002296
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002297 /* enable the connection monitoring feature */
2298 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002300 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301
2302 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002303 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2304 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002305 enum wl1271_cmd_ps_mode mode;
2306
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002307 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002308 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002309 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002310 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002312 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002314 } else {
2315 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002316 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002317 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002318 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002319
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002320 /* free probe-request template */
2321 dev_kfree_skb(wl->probereq);
2322 wl->probereq = NULL;
2323
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002324 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002325 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002326
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002327 /* revert back to minimum rates for the current band */
2328 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002329 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002330 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002331 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002332 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002334 /* disable connection monitor features */
2335 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002336
2337 /* Disable the keep-alive feature */
2338 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002339 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002340 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002341
2342 /* restore the bssid filter and go to dummy bssid */
2343 wl1271_unjoin(wl);
2344 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345 }
2346 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002347
Arik Nemtsove78a2872010-10-16 19:07:21 +02002348 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2349 if (ret < 0)
2350 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351
Shahar Levi18357852010-10-13 16:09:41 +02002352 /*
2353 * Takes care of: New association with HT enable,
2354 * HT information change in beacon.
2355 */
2356 if (sta &&
2357 (changed & BSS_CHANGED_HT) &&
2358 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2359 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2360 if (ret < 0) {
2361 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002362 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002363 }
2364 ret = wl1271_acx_set_ht_information(wl,
2365 bss_conf->ht_operation_mode);
2366 if (ret < 0) {
2367 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002368 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002369 }
2370 }
2371 /*
2372 * Takes care of: New association without HT,
2373 * Disassociation.
2374 */
2375 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2376 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2377 if (ret < 0) {
2378 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002379 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002380 }
2381 }
2382
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002383 if (changed & BSS_CHANGED_ARP_FILTER) {
2384 __be32 addr = bss_conf->arp_addr_list[0];
2385 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2386
Eliad Pellerc5312772010-12-09 11:31:27 +02002387 if (bss_conf->arp_addr_cnt == 1 &&
2388 bss_conf->arp_filter_enabled) {
2389 /*
2390 * The template should have been configured only upon
2391 * association. however, it seems that the correct ip
2392 * isn't being set (when sending), so we have to
2393 * reconfigure the template upon every ip change.
2394 */
2395 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2396 if (ret < 0) {
2397 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002398 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002399 }
2400
2401 ret = wl1271_acx_arp_ip_filter(wl,
2402 (ACX_ARP_FILTER_ARP_FILTERING |
2403 ACX_ARP_FILTER_AUTO_ARP),
2404 addr);
2405 } else
2406 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002407
2408 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002409 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002410 }
2411
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002412 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002413 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002414 if (ret < 0) {
2415 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002416 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002417 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002418 }
2419
Arik Nemtsove78a2872010-10-16 19:07:21 +02002420out:
2421 return;
2422}
2423
2424static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2425 struct ieee80211_vif *vif,
2426 struct ieee80211_bss_conf *bss_conf,
2427 u32 changed)
2428{
2429 struct wl1271 *wl = hw->priv;
2430 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2431 int ret;
2432
2433 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2434 (int)changed);
2435
2436 mutex_lock(&wl->mutex);
2437
2438 if (unlikely(wl->state == WL1271_STATE_OFF))
2439 goto out;
2440
2441 ret = wl1271_ps_elp_wakeup(wl, false);
2442 if (ret < 0)
2443 goto out;
2444
2445 if (is_ap)
2446 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2447 else
2448 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450 wl1271_ps_elp_sleep(wl);
2451
2452out:
2453 mutex_unlock(&wl->mutex);
2454}
2455
Kalle Valoc6999d82010-02-18 13:25:41 +02002456static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2457 const struct ieee80211_tx_queue_params *params)
2458{
2459 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002460 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002461 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002462
2463 mutex_lock(&wl->mutex);
2464
2465 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2466
Kalle Valo4695dc92010-03-18 12:26:38 +02002467 if (params->uapsd)
2468 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2469 else
2470 ps_scheme = CONF_PS_SCHEME_LEGACY;
2471
Arik Nemtsov488fc542010-10-16 20:33:45 +02002472 if (wl->state == WL1271_STATE_OFF) {
2473 /*
2474 * If the state is off, the parameters will be recorded and
2475 * configured on init. This happens in AP-mode.
2476 */
2477 struct conf_tx_ac_category *conf_ac =
2478 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2479 struct conf_tx_tid *conf_tid =
2480 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2481
2482 conf_ac->ac = wl1271_tx_get_queue(queue);
2483 conf_ac->cw_min = (u8)params->cw_min;
2484 conf_ac->cw_max = params->cw_max;
2485 conf_ac->aifsn = params->aifs;
2486 conf_ac->tx_op_limit = params->txop << 5;
2487
2488 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2489 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2490 conf_tid->tsid = wl1271_tx_get_queue(queue);
2491 conf_tid->ps_scheme = ps_scheme;
2492 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2493 conf_tid->apsd_conf[0] = 0;
2494 conf_tid->apsd_conf[1] = 0;
2495 } else {
2496 ret = wl1271_ps_elp_wakeup(wl, false);
2497 if (ret < 0)
2498 goto out;
2499
2500 /*
2501 * the txop is confed in units of 32us by the mac80211,
2502 * we need us
2503 */
2504 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2505 params->cw_min, params->cw_max,
2506 params->aifs, params->txop << 5);
2507 if (ret < 0)
2508 goto out_sleep;
2509
2510 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2511 CONF_CHANNEL_TYPE_EDCF,
2512 wl1271_tx_get_queue(queue),
2513 ps_scheme, CONF_ACK_POLICY_LEGACY,
2514 0, 0);
2515 if (ret < 0)
2516 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002517
2518out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002519 wl1271_ps_elp_sleep(wl);
2520 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002521
2522out:
2523 mutex_unlock(&wl->mutex);
2524
2525 return ret;
2526}
2527
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002528static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2529{
2530
2531 struct wl1271 *wl = hw->priv;
2532 u64 mactime = ULLONG_MAX;
2533 int ret;
2534
2535 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2536
2537 mutex_lock(&wl->mutex);
2538
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002539 if (unlikely(wl->state == WL1271_STATE_OFF))
2540 goto out;
2541
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002542 ret = wl1271_ps_elp_wakeup(wl, false);
2543 if (ret < 0)
2544 goto out;
2545
2546 ret = wl1271_acx_tsf_info(wl, &mactime);
2547 if (ret < 0)
2548 goto out_sleep;
2549
2550out_sleep:
2551 wl1271_ps_elp_sleep(wl);
2552
2553out:
2554 mutex_unlock(&wl->mutex);
2555 return mactime;
2556}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557
John W. Linvilleece550d2010-07-28 16:41:06 -04002558static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2559 struct survey_info *survey)
2560{
2561 struct wl1271 *wl = hw->priv;
2562 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002563
John W. Linvilleece550d2010-07-28 16:41:06 -04002564 if (idx != 0)
2565 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002566
John W. Linvilleece550d2010-07-28 16:41:06 -04002567 survey->channel = conf->channel;
2568 survey->filled = SURVEY_INFO_NOISE_DBM;
2569 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002570
John W. Linvilleece550d2010-07-28 16:41:06 -04002571 return 0;
2572}
2573
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002574static int wl1271_allocate_hlid(struct wl1271 *wl,
2575 struct ieee80211_sta *sta,
2576 u8 *hlid)
2577{
2578 struct wl1271_station *wl_sta;
2579 int id;
2580
2581 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2582 if (id >= AP_MAX_STATIONS) {
2583 wl1271_warning("could not allocate HLID - too much stations");
2584 return -EBUSY;
2585 }
2586
2587 wl_sta = (struct wl1271_station *)sta->drv_priv;
2588
2589 __set_bit(id, wl->ap_hlid_map);
2590 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2591 *hlid = wl_sta->hlid;
2592 return 0;
2593}
2594
2595static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2596{
2597 int id = hlid - WL1271_AP_STA_HLID_START;
2598
2599 __clear_bit(id, wl->ap_hlid_map);
2600}
2601
2602static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2603 struct ieee80211_vif *vif,
2604 struct ieee80211_sta *sta)
2605{
2606 struct wl1271 *wl = hw->priv;
2607 int ret = 0;
2608 u8 hlid;
2609
2610 mutex_lock(&wl->mutex);
2611
2612 if (unlikely(wl->state == WL1271_STATE_OFF))
2613 goto out;
2614
2615 if (wl->bss_type != BSS_TYPE_AP_BSS)
2616 goto out;
2617
2618 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2619
2620 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2621 if (ret < 0)
2622 goto out;
2623
2624 ret = wl1271_ps_elp_wakeup(wl, false);
2625 if (ret < 0)
2626 goto out;
2627
2628 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2629 if (ret < 0)
2630 goto out_sleep;
2631
2632out_sleep:
2633 wl1271_ps_elp_sleep(wl);
2634
2635out:
2636 mutex_unlock(&wl->mutex);
2637 return ret;
2638}
2639
2640static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2641 struct ieee80211_vif *vif,
2642 struct ieee80211_sta *sta)
2643{
2644 struct wl1271 *wl = hw->priv;
2645 struct wl1271_station *wl_sta;
2646 int ret = 0, id;
2647
2648 mutex_lock(&wl->mutex);
2649
2650 if (unlikely(wl->state == WL1271_STATE_OFF))
2651 goto out;
2652
2653 if (wl->bss_type != BSS_TYPE_AP_BSS)
2654 goto out;
2655
2656 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2657
2658 wl_sta = (struct wl1271_station *)sta->drv_priv;
2659 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2660 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2661 goto out;
2662
2663 ret = wl1271_ps_elp_wakeup(wl, false);
2664 if (ret < 0)
2665 goto out;
2666
2667 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2668 if (ret < 0)
2669 goto out_sleep;
2670
2671 wl1271_free_hlid(wl, wl_sta->hlid);
2672
2673out_sleep:
2674 wl1271_ps_elp_sleep(wl);
2675
2676out:
2677 mutex_unlock(&wl->mutex);
2678 return ret;
2679}
2680
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681/* can't be const, mac80211 writes to this */
2682static struct ieee80211_rate wl1271_rates[] = {
2683 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002684 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2685 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002687 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2688 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2690 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002691 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2692 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2694 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002695 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2696 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2698 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002699 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2700 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002702 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2703 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002705 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2706 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002707 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002708 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2709 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002710 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002711 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2712 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002714 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2715 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002717 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2718 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002720 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2721 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722};
2723
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002724/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002726 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002727 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002728 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2729 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2730 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002731 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002732 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2733 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2734 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002735 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002736 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2737 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2738 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002739};
2740
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002741/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002742static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002743 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002744 7, /* CONF_HW_RXTX_RATE_MCS7 */
2745 6, /* CONF_HW_RXTX_RATE_MCS6 */
2746 5, /* CONF_HW_RXTX_RATE_MCS5 */
2747 4, /* CONF_HW_RXTX_RATE_MCS4 */
2748 3, /* CONF_HW_RXTX_RATE_MCS3 */
2749 2, /* CONF_HW_RXTX_RATE_MCS2 */
2750 1, /* CONF_HW_RXTX_RATE_MCS1 */
2751 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002752
2753 11, /* CONF_HW_RXTX_RATE_54 */
2754 10, /* CONF_HW_RXTX_RATE_48 */
2755 9, /* CONF_HW_RXTX_RATE_36 */
2756 8, /* CONF_HW_RXTX_RATE_24 */
2757
2758 /* TI-specific rate */
2759 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2760
2761 7, /* CONF_HW_RXTX_RATE_18 */
2762 6, /* CONF_HW_RXTX_RATE_12 */
2763 3, /* CONF_HW_RXTX_RATE_11 */
2764 5, /* CONF_HW_RXTX_RATE_9 */
2765 4, /* CONF_HW_RXTX_RATE_6 */
2766 2, /* CONF_HW_RXTX_RATE_5_5 */
2767 1, /* CONF_HW_RXTX_RATE_2 */
2768 0 /* CONF_HW_RXTX_RATE_1 */
2769};
2770
Shahar Levie8b03a22010-10-13 16:09:39 +02002771/* 11n STA capabilities */
2772#define HW_RX_HIGHEST_RATE 72
2773
Shahar Levi00d20102010-11-08 11:20:10 +00002774#ifdef CONFIG_WL12XX_HT
2775#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002776 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2777 .ht_supported = true, \
2778 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2779 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2780 .mcs = { \
2781 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2782 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2783 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2784 }, \
2785}
Shahar Levi18357852010-10-13 16:09:41 +02002786#else
Shahar Levi00d20102010-11-08 11:20:10 +00002787#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002788 .ht_supported = false, \
2789}
2790#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002791
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002792/* can't be const, mac80211 writes to this */
2793static struct ieee80211_supported_band wl1271_band_2ghz = {
2794 .channels = wl1271_channels,
2795 .n_channels = ARRAY_SIZE(wl1271_channels),
2796 .bitrates = wl1271_rates,
2797 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002798 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799};
2800
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002801/* 5 GHz data rates for WL1273 */
2802static struct ieee80211_rate wl1271_rates_5ghz[] = {
2803 { .bitrate = 60,
2804 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2805 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2806 { .bitrate = 90,
2807 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2808 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2809 { .bitrate = 120,
2810 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2811 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2812 { .bitrate = 180,
2813 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2814 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2815 { .bitrate = 240,
2816 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2817 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2818 { .bitrate = 360,
2819 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2820 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2821 { .bitrate = 480,
2822 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2823 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2824 { .bitrate = 540,
2825 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2826 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2827};
2828
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002829/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002830static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002831 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002832 { .hw_value = 8, .center_freq = 5040},
2833 { .hw_value = 9, .center_freq = 5045},
2834 { .hw_value = 11, .center_freq = 5055},
2835 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002836 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002837 { .hw_value = 34, .center_freq = 5170},
2838 { .hw_value = 36, .center_freq = 5180},
2839 { .hw_value = 38, .center_freq = 5190},
2840 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002841 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002842 { .hw_value = 44, .center_freq = 5220},
2843 { .hw_value = 46, .center_freq = 5230},
2844 { .hw_value = 48, .center_freq = 5240},
2845 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002846 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002847 { .hw_value = 60, .center_freq = 5300},
2848 { .hw_value = 64, .center_freq = 5320},
2849 { .hw_value = 100, .center_freq = 5500},
2850 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002851 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002852 { .hw_value = 112, .center_freq = 5560},
2853 { .hw_value = 116, .center_freq = 5580},
2854 { .hw_value = 120, .center_freq = 5600},
2855 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002856 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002857 { .hw_value = 132, .center_freq = 5660},
2858 { .hw_value = 136, .center_freq = 5680},
2859 { .hw_value = 140, .center_freq = 5700},
2860 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002861 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002862 { .hw_value = 157, .center_freq = 5785},
2863 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002864 { .hw_value = 165, .center_freq = 5825},
2865};
2866
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002867/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002868static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002869 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002870 7, /* CONF_HW_RXTX_RATE_MCS7 */
2871 6, /* CONF_HW_RXTX_RATE_MCS6 */
2872 5, /* CONF_HW_RXTX_RATE_MCS5 */
2873 4, /* CONF_HW_RXTX_RATE_MCS4 */
2874 3, /* CONF_HW_RXTX_RATE_MCS3 */
2875 2, /* CONF_HW_RXTX_RATE_MCS2 */
2876 1, /* CONF_HW_RXTX_RATE_MCS1 */
2877 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002878
2879 7, /* CONF_HW_RXTX_RATE_54 */
2880 6, /* CONF_HW_RXTX_RATE_48 */
2881 5, /* CONF_HW_RXTX_RATE_36 */
2882 4, /* CONF_HW_RXTX_RATE_24 */
2883
2884 /* TI-specific rate */
2885 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2886
2887 3, /* CONF_HW_RXTX_RATE_18 */
2888 2, /* CONF_HW_RXTX_RATE_12 */
2889 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2890 1, /* CONF_HW_RXTX_RATE_9 */
2891 0, /* CONF_HW_RXTX_RATE_6 */
2892 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2893 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2894 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2895};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002896
2897static struct ieee80211_supported_band wl1271_band_5ghz = {
2898 .channels = wl1271_channels_5ghz,
2899 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2900 .bitrates = wl1271_rates_5ghz,
2901 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002902 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002903};
2904
Tobias Klausera0ea9492010-05-20 10:38:11 +02002905static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002906 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2907 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2908};
2909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910static const struct ieee80211_ops wl1271_ops = {
2911 .start = wl1271_op_start,
2912 .stop = wl1271_op_stop,
2913 .add_interface = wl1271_op_add_interface,
2914 .remove_interface = wl1271_op_remove_interface,
2915 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002916 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 .configure_filter = wl1271_op_configure_filter,
2918 .tx = wl1271_op_tx,
2919 .set_key = wl1271_op_set_key,
2920 .hw_scan = wl1271_op_hw_scan,
2921 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002922 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002924 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002925 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002926 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002927 .sta_add = wl1271_op_sta_add,
2928 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002929 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930};
2931
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002932
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002933u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002934{
2935 u8 idx;
2936
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002937 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002938
2939 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2940 wl1271_error("Illegal RX rate from HW: %d", rate);
2941 return 0;
2942 }
2943
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002944 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002945 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2946 wl1271_error("Unsupported RX rate from HW: %d", rate);
2947 return 0;
2948 }
2949
2950 return idx;
2951}
2952
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002953static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2954 struct device_attribute *attr,
2955 char *buf)
2956{
2957 struct wl1271 *wl = dev_get_drvdata(dev);
2958 ssize_t len;
2959
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002960 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002961
2962 mutex_lock(&wl->mutex);
2963 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2964 wl->sg_enabled);
2965 mutex_unlock(&wl->mutex);
2966
2967 return len;
2968
2969}
2970
2971static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2972 struct device_attribute *attr,
2973 const char *buf, size_t count)
2974{
2975 struct wl1271 *wl = dev_get_drvdata(dev);
2976 unsigned long res;
2977 int ret;
2978
2979 ret = strict_strtoul(buf, 10, &res);
2980
2981 if (ret < 0) {
2982 wl1271_warning("incorrect value written to bt_coex_mode");
2983 return count;
2984 }
2985
2986 mutex_lock(&wl->mutex);
2987
2988 res = !!res;
2989
2990 if (res == wl->sg_enabled)
2991 goto out;
2992
2993 wl->sg_enabled = res;
2994
2995 if (wl->state == WL1271_STATE_OFF)
2996 goto out;
2997
2998 ret = wl1271_ps_elp_wakeup(wl, false);
2999 if (ret < 0)
3000 goto out;
3001
3002 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3003 wl1271_ps_elp_sleep(wl);
3004
3005 out:
3006 mutex_unlock(&wl->mutex);
3007 return count;
3008}
3009
3010static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3011 wl1271_sysfs_show_bt_coex_state,
3012 wl1271_sysfs_store_bt_coex_state);
3013
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003014static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3015 struct device_attribute *attr,
3016 char *buf)
3017{
3018 struct wl1271 *wl = dev_get_drvdata(dev);
3019 ssize_t len;
3020
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003021 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003022
3023 mutex_lock(&wl->mutex);
3024 if (wl->hw_pg_ver >= 0)
3025 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3026 else
3027 len = snprintf(buf, len, "n/a\n");
3028 mutex_unlock(&wl->mutex);
3029
3030 return len;
3031}
3032
3033static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3034 wl1271_sysfs_show_hw_pg_ver, NULL);
3035
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003036int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037{
3038 int ret;
3039
3040 if (wl->mac80211_registered)
3041 return 0;
3042
3043 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3044
3045 ret = ieee80211_register_hw(wl->hw);
3046 if (ret < 0) {
3047 wl1271_error("unable to register mac80211 hw: %d", ret);
3048 return ret;
3049 }
3050
3051 wl->mac80211_registered = true;
3052
Eliad Pellerd60080a2010-11-24 12:53:16 +02003053 wl1271_debugfs_init(wl);
3054
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003055 register_netdevice_notifier(&wl1271_dev_notifier);
3056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003057 wl1271_notice("loaded");
3058
3059 return 0;
3060}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003061EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003063void wl1271_unregister_hw(struct wl1271 *wl)
3064{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003065 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003066 ieee80211_unregister_hw(wl->hw);
3067 wl->mac80211_registered = false;
3068
3069}
3070EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3071
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003072int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003074 static const u32 cipher_suites[] = {
3075 WLAN_CIPHER_SUITE_WEP40,
3076 WLAN_CIPHER_SUITE_WEP104,
3077 WLAN_CIPHER_SUITE_TKIP,
3078 WLAN_CIPHER_SUITE_CCMP,
3079 WL1271_CIPHER_SUITE_GEM,
3080 };
3081
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003082 /* The tx descriptor buffer and the TKIP space. */
3083 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3084 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003085
3086 /* unit us */
3087 /* FIXME: find a proper value */
3088 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003089 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090
3091 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003092 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003093 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003094 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003095 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003096 IEEE80211_HW_CONNECTION_MONITOR |
3097 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003098
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003099 wl->hw->wiphy->cipher_suites = cipher_suites;
3100 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3101
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003102 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
3103 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003104 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003105 /*
3106 * Maximum length of elements in scanning probe request templates
3107 * should be the maximum length possible for a template, without
3108 * the IEEE80211 header of the template
3109 */
3110 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3111 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03003113 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003114
Kalle Valo12bd8942010-03-18 12:26:33 +02003115 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003116 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003117
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003118 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3119
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003120 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003121
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003122 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003124 return 0;
3125}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003126EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003128#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003129
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003130struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003132 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003133 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003134 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003135 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003136 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137
3138 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3139 if (!hw) {
3140 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003141 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003142 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143 }
3144
Julia Lawall929ebd32010-05-15 23:16:39 +02003145 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003146 if (!plat_dev) {
3147 wl1271_error("could not allocate platform_device");
3148 ret = -ENOMEM;
3149 goto err_plat_alloc;
3150 }
3151
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003152 wl = hw->priv;
3153 memset(wl, 0, sizeof(*wl));
3154
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003155 INIT_LIST_HEAD(&wl->list);
3156
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003157 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003158 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003160 for (i = 0; i < NUM_TX_QUEUES; i++)
3161 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003163 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003164 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003165 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3166 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3167 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3168 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003169 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003170 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003171 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003172 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003173 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3174 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003175 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003176 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003177 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003178 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003179 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3180 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003181 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003182 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003183 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003184 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003185 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003186
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003187 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003188 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003189 wl->tx_frames[i] = NULL;
3190
3191 spin_lock_init(&wl->wl_lock);
3192
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003193 wl->state = WL1271_STATE_OFF;
3194 mutex_init(&wl->mutex);
3195
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003196 /* Apply default driver configuration. */
3197 wl1271_conf_init(wl);
3198
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003199 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3200 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3201 if (!wl->aggr_buf) {
3202 ret = -ENOMEM;
3203 goto err_hw;
3204 }
3205
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003206 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003207 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003208 if (ret) {
3209 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003210 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003211 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003212 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003213
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003214 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003215 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003216 if (ret < 0) {
3217 wl1271_error("failed to create sysfs file bt_coex_state");
3218 goto err_platform;
3219 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003220
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003221 /* Create sysfs file to get HW PG version */
3222 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3223 if (ret < 0) {
3224 wl1271_error("failed to create sysfs file hw_pg_ver");
3225 goto err_bt_coex_state;
3226 }
3227
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003228 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003229
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003230err_bt_coex_state:
3231 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3232
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003233err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003234 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003235
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003236err_aggr:
3237 free_pages((unsigned long)wl->aggr_buf, order);
3238
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003239err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003240 wl1271_debugfs_exit(wl);
3241 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003242
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003243err_plat_alloc:
3244 ieee80211_free_hw(hw);
3245
3246err_hw_alloc:
3247
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003248 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003249}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003250EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003251
3252int wl1271_free_hw(struct wl1271 *wl)
3253{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003254 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003255 free_pages((unsigned long)wl->aggr_buf,
3256 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003257 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003258
3259 wl1271_debugfs_exit(wl);
3260
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003261 vfree(wl->fw);
3262 wl->fw = NULL;
3263 kfree(wl->nvs);
3264 wl->nvs = NULL;
3265
3266 kfree(wl->fw_status);
3267 kfree(wl->tx_res_if);
3268
3269 ieee80211_free_hw(wl->hw);
3270
3271 return 0;
3272}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003273EXPORT_SYMBOL_GPL(wl1271_free_hw);
3274
Eliad Peller17c17552010-12-12 12:15:35 +02003275u32 wl12xx_debug_level;
3276EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3277module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3278MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3279
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003280MODULE_LICENSE("GPL");
3281MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3282MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");