blob: 8a35491629992cfd41c1673032c002c03b9b6552 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
259 .psm_entry_nullfunc_retries = 3,
260 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300261 .keep_alive_interval = 55000,
262 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200264 .itrim = {
265 .enable = false,
266 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200267 },
268 .pm_config = {
269 .host_clk_settling_time = 5000,
270 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300271 },
272 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300273 .trigger_pacing = 1,
274 .avg_weight_rssi_beacon = 20,
275 .avg_weight_rssi_data = 10,
276 .avg_weight_snr_beacon = 20,
277 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200278 },
279 .scan = {
280 .min_dwell_time_active = 7500,
281 .max_dwell_time_active = 30000,
282 .min_dwell_time_passive = 30000,
283 .max_dwell_time_passive = 60000,
284 .num_probe_reqs = 2,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300296};
297
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200298static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200299static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200300
301
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200302static void wl1271_device_release(struct device *dev)
303{
304
305}
306
307static struct platform_device wl1271_device = {
308 .name = "wl1271",
309 .id = -1,
310
311 /* device model insists to have a release function */
312 .dev = {
313 .release = wl1271_device_release,
314 },
315};
316
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300317static LIST_HEAD(wl_list);
318
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300319static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
320 void *arg)
321{
322 struct net_device *dev = arg;
323 struct wireless_dev *wdev;
324 struct wiphy *wiphy;
325 struct ieee80211_hw *hw;
326 struct wl1271 *wl;
327 struct wl1271 *wl_temp;
328 int ret = 0;
329
330 /* Check that this notification is for us. */
331 if (what != NETDEV_CHANGE)
332 return NOTIFY_DONE;
333
334 wdev = dev->ieee80211_ptr;
335 if (wdev == NULL)
336 return NOTIFY_DONE;
337
338 wiphy = wdev->wiphy;
339 if (wiphy == NULL)
340 return NOTIFY_DONE;
341
342 hw = wiphy_priv(wiphy);
343 if (hw == NULL)
344 return NOTIFY_DONE;
345
346 wl_temp = hw->priv;
347 list_for_each_entry(wl, &wl_list, list) {
348 if (wl == wl_temp)
349 break;
350 }
351 if (wl != wl_temp)
352 return NOTIFY_DONE;
353
354 mutex_lock(&wl->mutex);
355
356 if (wl->state == WL1271_STATE_OFF)
357 goto out;
358
359 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
360 goto out;
361
362 ret = wl1271_ps_elp_wakeup(wl, false);
363 if (ret < 0)
364 goto out;
365
366 if ((dev->operstate == IF_OPER_UP) &&
367 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
368 wl1271_cmd_set_sta_state(wl);
369 wl1271_info("Association completed.");
370 }
371
372 wl1271_ps_elp_sleep(wl);
373
374out:
375 mutex_unlock(&wl->mutex);
376
377 return NOTIFY_OK;
378}
379
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100380static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200381 struct regulatory_request *request)
382{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100383 struct ieee80211_supported_band *band;
384 struct ieee80211_channel *ch;
385 int i;
386
387 band = wiphy->bands[IEEE80211_BAND_5GHZ];
388 for (i = 0; i < band->n_channels; i++) {
389 ch = &band->channels[i];
390 if (ch->flags & IEEE80211_CHAN_DISABLED)
391 continue;
392
393 if (ch->flags & IEEE80211_CHAN_RADAR)
394 ch->flags |= IEEE80211_CHAN_NO_IBSS |
395 IEEE80211_CHAN_PASSIVE_SCAN;
396
397 }
398
399 return 0;
400}
401
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300402static void wl1271_conf_init(struct wl1271 *wl)
403{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300404
405 /*
406 * This function applies the default configuration to the driver. This
407 * function is invoked upon driver load (spi probe.)
408 *
409 * The configuration is stored in a run-time structure in order to
410 * facilitate for run-time adjustment of any of the parameters. Making
411 * changes to the configuration structure will apply the new values on
412 * the next interface up (wl1271_op_start.)
413 */
414
415 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300416 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417}
418
419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420static int wl1271_plt_init(struct wl1271 *wl)
421{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200422 struct conf_tx_ac_category *conf_ac;
423 struct conf_tx_tid *conf_tid;
424 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200426 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200427 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200428 return ret;
429
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200430 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200431 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200432 return ret;
433
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200434 ret = wl1271_cmd_ext_radio_parms(wl);
435 if (ret < 0)
436 return ret;
437
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200438 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200439 if (ret < 0)
440 return ret;
441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 ret = wl1271_acx_init_mem_config(wl);
443 if (ret < 0)
444 return ret;
445
Luciano Coelho12419cc2010-02-18 13:25:44 +0200446 /* PHY layer config */
447 ret = wl1271_init_phy_config(wl);
448 if (ret < 0)
449 goto out_free_memmap;
450
451 ret = wl1271_acx_dco_itrim_params(wl);
452 if (ret < 0)
453 goto out_free_memmap;
454
455 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200456 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200457 if (ret < 0)
458 goto out_free_memmap;
459
460 /* Bluetooth WLAN coexistence */
461 ret = wl1271_init_pta(wl);
462 if (ret < 0)
463 goto out_free_memmap;
464
465 /* Energy detection */
466 ret = wl1271_init_energy_detection(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100471 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200475 /* Default TID/AC configuration */
476 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200477 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200478 conf_ac = &wl->conf.tx.ac_conf[i];
479 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
480 conf_ac->cw_max, conf_ac->aifsn,
481 conf_ac->tx_op_limit);
482 if (ret < 0)
483 goto out_free_memmap;
484
Luciano Coelho12419cc2010-02-18 13:25:44 +0200485 conf_tid = &wl->conf.tx.tid_conf[i];
486 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
487 conf_tid->channel_type,
488 conf_tid->tsid,
489 conf_tid->ps_scheme,
490 conf_tid->ack_policy,
491 conf_tid->apsd_conf[0],
492 conf_tid->apsd_conf[1]);
493 if (ret < 0)
494 goto out_free_memmap;
495 }
496
Luciano Coelho12419cc2010-02-18 13:25:44 +0200497 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200498 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200500 goto out_free_memmap;
501
502 /* Configure for CAM power saving (ie. always active) */
503 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
504 if (ret < 0)
505 goto out_free_memmap;
506
507 /* configure PM */
508 ret = wl1271_acx_pm_config(wl);
509 if (ret < 0)
510 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511
512 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200513
514 out_free_memmap:
515 kfree(wl->target_mem_map);
516 wl->target_mem_map = NULL;
517
518 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519}
520
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300521static void wl1271_fw_status(struct wl1271 *wl,
522 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200524 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525 u32 total = 0;
526 int i;
527
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200528 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529
530 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
531 "drv_rx_counter = %d, tx_results_counter = %d)",
532 status->intr,
533 status->fw_rx_counter,
534 status->drv_rx_counter,
535 status->tx_results_counter);
536
537 /* update number of available TX blocks */
538 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300539 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
540 wl->tx_blocks_freed[i];
541
542 wl->tx_blocks_freed[i] =
543 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544 wl->tx_blocks_available += cnt;
545 total += cnt;
546 }
547
Ido Yariva5225502010-10-12 14:49:10 +0200548 /* if more blocks are available now, tx work can be scheduled */
549 if (total)
550 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300551
552 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200553 getnstimeofday(&ts);
554 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
555 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556}
557
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200558#define WL1271_IRQ_MAX_LOOPS 10
559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560static void wl1271_irq_work(struct work_struct *work)
561{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300563 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200564 int loopcount = WL1271_IRQ_MAX_LOOPS;
565 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300566 struct wl1271 *wl =
567 container_of(work, struct wl1271, irq_work);
568
569 mutex_lock(&wl->mutex);
570
571 wl1271_debug(DEBUG_IRQ, "IRQ work");
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300574 goto out;
575
576 ret = wl1271_ps_elp_wakeup(wl, true);
577 if (ret < 0)
578 goto out;
579
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200580 spin_lock_irqsave(&wl->wl_lock, flags);
581 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
582 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
583 spin_unlock_irqrestore(&wl->wl_lock, flags);
584 loopcount--;
585
586 wl1271_fw_status(wl, wl->fw_status);
587 intr = le32_to_cpu(wl->fw_status->intr);
588 if (!intr) {
589 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200590 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200591 continue;
592 }
593
594 intr &= WL1271_INTR_MASK;
595
Eliad Pellerccc83b02010-10-27 14:09:57 +0200596 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
597 wl1271_error("watchdog interrupt received! "
598 "starting recovery.");
599 ieee80211_queue_work(wl->hw, &wl->recovery_work);
600
601 /* restarting the chip. ignore any other interrupt. */
602 goto out;
603 }
604
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 if (intr & WL1271_ACX_INTR_DATA) {
606 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
607
608 /* check for tx results */
609 if (wl->fw_status->tx_results_counter !=
610 (wl->tx_results_count & 0xff))
611 wl1271_tx_complete(wl);
612
Ido Yariva5225502010-10-12 14:49:10 +0200613 /* Check if any tx blocks were freed */
614 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200615 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200616 /*
617 * In order to avoid starvation of the TX path,
618 * call the work function directly.
619 */
620 wl1271_tx_work_locked(wl);
621 }
622
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200623 wl1271_rx(wl, wl->fw_status);
624 }
625
626 if (intr & WL1271_ACX_INTR_EVENT_A) {
627 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
628 wl1271_event_handle(wl, 0);
629 }
630
631 if (intr & WL1271_ACX_INTR_EVENT_B) {
632 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
633 wl1271_event_handle(wl, 1);
634 }
635
636 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
637 wl1271_debug(DEBUG_IRQ,
638 "WL1271_ACX_INTR_INIT_COMPLETE");
639
640 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
641 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
642
643 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644 }
645
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200646 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
647 ieee80211_queue_work(wl->hw, &wl->irq_work);
648 else
649 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
650 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652 wl1271_ps_elp_sleep(wl);
653
654out:
655 mutex_unlock(&wl->mutex);
656}
657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658static int wl1271_fetch_firmware(struct wl1271 *wl)
659{
660 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200661 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 int ret;
663
Arik Nemtsov166d5042010-10-16 21:44:57 +0200664 switch (wl->bss_type) {
665 case BSS_TYPE_AP_BSS:
666 fw_name = WL1271_AP_FW_NAME;
667 break;
668 case BSS_TYPE_IBSS:
669 case BSS_TYPE_STA_BSS:
670 fw_name = WL1271_FW_NAME;
671 break;
672 default:
673 wl1271_error("no compatible firmware for bss_type %d",
674 wl->bss_type);
675 return -EINVAL;
676 }
677
678 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
679
680 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681
682 if (ret < 0) {
683 wl1271_error("could not get firmware: %d", ret);
684 return ret;
685 }
686
687 if (fw->size % 4) {
688 wl1271_error("firmware size is not multiple of 32 bits: %zu",
689 fw->size);
690 ret = -EILSEQ;
691 goto out;
692 }
693
Arik Nemtsov166d5042010-10-16 21:44:57 +0200694 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300696 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697
698 if (!wl->fw) {
699 wl1271_error("could not allocate memory for the firmware");
700 ret = -ENOMEM;
701 goto out;
702 }
703
704 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200705 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 ret = 0;
707
708out:
709 release_firmware(fw);
710
711 return ret;
712}
713
714static int wl1271_fetch_nvs(struct wl1271 *wl)
715{
716 const struct firmware *fw;
717 int ret;
718
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200719 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720
721 if (ret < 0) {
722 wl1271_error("could not get nvs file: %d", ret);
723 return ret;
724 }
725
Julia Lawall929ebd32010-05-15 23:16:39 +0200726 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727
728 if (!wl->nvs) {
729 wl1271_error("could not allocate memory for the nvs file");
730 ret = -ENOMEM;
731 goto out;
732 }
733
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200734 wl->nvs_len = fw->size;
735
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736out:
737 release_firmware(fw);
738
739 return ret;
740}
741
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200742static void wl1271_recovery_work(struct work_struct *work)
743{
744 struct wl1271 *wl =
745 container_of(work, struct wl1271, recovery_work);
746
747 mutex_lock(&wl->mutex);
748
749 if (wl->state != WL1271_STATE_ON)
750 goto out;
751
752 wl1271_info("Hardware recovery in progress.");
753
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200754 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
755 ieee80211_connection_loss(wl->vif);
756
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200757 /* reboot the chipset */
758 __wl1271_op_remove_interface(wl);
759 ieee80211_restart_hw(wl->hw);
760
761out:
762 mutex_unlock(&wl->mutex);
763}
764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765static void wl1271_fw_wakeup(struct wl1271 *wl)
766{
767 u32 elp_reg;
768
769 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300770 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771}
772
773static int wl1271_setup(struct wl1271 *wl)
774{
775 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
776 if (!wl->fw_status)
777 return -ENOMEM;
778
779 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
780 if (!wl->tx_res_if) {
781 kfree(wl->fw_status);
782 return -ENOMEM;
783 }
784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 return 0;
786}
787
788static int wl1271_chip_wakeup(struct wl1271 *wl)
789{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300790 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 int ret = 0;
792
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200793 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200794 ret = wl1271_power_on(wl);
795 if (ret < 0)
796 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200798 wl1271_io_reset(wl);
799 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 /* We don't need a real memory partition here, because we only want
802 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300803 memset(&partition, 0, sizeof(partition));
804 partition.reg.start = REGISTERS_BASE;
805 partition.reg.size = REGISTERS_DOWN_SIZE;
806 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
808 /* ELP module wake up */
809 wl1271_fw_wakeup(wl);
810
811 /* whal_FwCtrl_BootSm() */
812
813 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200814 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815
816 /* 1. check if chip id is valid */
817
818 switch (wl->chip.id) {
819 case CHIP_ID_1271_PG10:
820 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
821 wl->chip.id);
822
823 ret = wl1271_setup(wl);
824 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200825 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 break;
827 case CHIP_ID_1271_PG20:
828 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
829 wl->chip.id);
830
831 ret = wl1271_setup(wl);
832 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200833 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 break;
835 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200836 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200838 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 }
840
Arik Nemtsov166d5042010-10-16 21:44:57 +0200841 /* Make sure the firmware type matches the BSS type */
842 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 ret = wl1271_fetch_firmware(wl);
844 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200845 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 }
847
848 /* No NVS from netlink, try to get it from the filesystem */
849 if (wl->nvs == NULL) {
850 ret = wl1271_fetch_nvs(wl);
851 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200852 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 }
854
855out:
856 return ret;
857}
858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859int wl1271_plt_start(struct wl1271 *wl)
860{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200861 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 int ret;
863
864 mutex_lock(&wl->mutex);
865
866 wl1271_notice("power up");
867
868 if (wl->state != WL1271_STATE_OFF) {
869 wl1271_error("cannot go into PLT state because not "
870 "in off state: %d", wl->state);
871 ret = -EBUSY;
872 goto out;
873 }
874
Arik Nemtsov166d5042010-10-16 21:44:57 +0200875 wl->bss_type = BSS_TYPE_STA_BSS;
876
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200877 while (retries) {
878 retries--;
879 ret = wl1271_chip_wakeup(wl);
880 if (ret < 0)
881 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200883 ret = wl1271_boot(wl);
884 if (ret < 0)
885 goto power_off;
886
887 ret = wl1271_plt_init(wl);
888 if (ret < 0)
889 goto irq_disable;
890
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200891 wl->state = WL1271_STATE_PLT;
892 wl1271_notice("firmware booted in PLT mode (%s)",
893 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 goto out;
895
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200896irq_disable:
897 wl1271_disable_interrupts(wl);
898 mutex_unlock(&wl->mutex);
899 /* Unlocking the mutex in the middle of handling is
900 inherently unsafe. In this case we deem it safe to do,
901 because we need to let any possibly pending IRQ out of
902 the system (and while we are WL1271_STATE_OFF the IRQ
903 work function will not do anything.) Also, any other
904 possible concurrent operations will fail due to the
905 current state, hence the wl1271 struct should be safe. */
906 cancel_work_sync(&wl->irq_work);
907 mutex_lock(&wl->mutex);
908power_off:
909 wl1271_power_off(wl);
910 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 wl1271_error("firmware boot in PLT mode failed despite %d retries",
913 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914out:
915 mutex_unlock(&wl->mutex);
916
917 return ret;
918}
919
920int wl1271_plt_stop(struct wl1271 *wl)
921{
922 int ret = 0;
923
924 mutex_lock(&wl->mutex);
925
926 wl1271_notice("power down");
927
928 if (wl->state != WL1271_STATE_PLT) {
929 wl1271_error("cannot power down because not in PLT "
930 "state: %d", wl->state);
931 ret = -EBUSY;
932 goto out;
933 }
934
935 wl1271_disable_interrupts(wl);
936 wl1271_power_off(wl);
937
938 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300939 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
941out:
942 mutex_unlock(&wl->mutex);
943
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200944 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200945 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200946
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 return ret;
948}
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
951{
952 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200953 struct ieee80211_conf *conf = &hw->conf;
954 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
955 struct ieee80211_sta *sta = txinfo->control.sta;
956 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200957 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
Shahar Levi18357852010-10-13 16:09:41 +0200959 /*
960 * peek into the rates configured in the STA entry.
961 * The rates set after connection stage, The first block only BG sets:
962 * the compare is for bit 0-16 of sta_rate_set. The second block add
963 * HT rates in case of HT supported.
964 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200965 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200966 if (sta &&
967 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200968 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
969 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200970 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
971 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
972 }
Shahar Levi18357852010-10-13 16:09:41 +0200973
Shahar Levi00d20102010-11-08 11:20:10 +0000974#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200975 if (sta &&
976 sta->ht_cap.ht_supported &&
977 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
978 sta->ht_cap.mcs.rx_mask[0])) {
979 /* Clean MCS bits before setting them */
980 wl->sta_rate_set &= HW_BG_RATES_MASK;
981 wl->sta_rate_set |=
982 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
983 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
984 }
985#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200986 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200987 spin_unlock_irqrestore(&wl->wl_lock, flags);
988
989 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200990 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
991 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992
993 /*
994 * The chip specific setup must run before the first TX packet -
995 * before that, the tx_work will not be initialized!
996 */
997
Ido Yariva5225502010-10-12 14:49:10 +0200998 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
999 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000
1001 /*
1002 * The workqueue is slow to process the tx_queue and we need stop
1003 * the queue here, otherwise the queue will get too long.
1004 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001005 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001006 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001008 spin_lock_irqsave(&wl->wl_lock, flags);
1009 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001010 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001011 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 }
1013
1014 return NETDEV_TX_OK;
1015}
1016
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001017static struct notifier_block wl1271_dev_notifier = {
1018 .notifier_call = wl1271_dev_notify,
1019};
1020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021static int wl1271_op_start(struct ieee80211_hw *hw)
1022{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001023 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1024
1025 /*
1026 * We have to delay the booting of the hardware because
1027 * we need to know the local MAC address before downloading and
1028 * initializing the firmware. The MAC address cannot be changed
1029 * after boot, and without the proper MAC address, the firmware
1030 * will not function properly.
1031 *
1032 * The MAC address is first known when the corresponding interface
1033 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001034 *
1035 * In addition, we currently have different firmwares for AP and managed
1036 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001037 */
1038
1039 return 0;
1040}
1041
1042static void wl1271_op_stop(struct ieee80211_hw *hw)
1043{
1044 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1045}
1046
1047static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1048 struct ieee80211_vif *vif)
1049{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001051 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001052 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001054 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001056 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1057 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
1059 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001060 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001061 wl1271_debug(DEBUG_MAC80211,
1062 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001063 ret = -EBUSY;
1064 goto out;
1065 }
1066
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001067 switch (vif->type) {
1068 case NL80211_IFTYPE_STATION:
1069 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001070 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001071 break;
1072 case NL80211_IFTYPE_ADHOC:
1073 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001074 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001075 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001076 case NL80211_IFTYPE_AP:
1077 wl->bss_type = BSS_TYPE_AP_BSS;
1078 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001079 default:
1080 ret = -EOPNOTSUPP;
1081 goto out;
1082 }
1083
1084 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085
1086 if (wl->state != WL1271_STATE_OFF) {
1087 wl1271_error("cannot start because not in off state: %d",
1088 wl->state);
1089 ret = -EBUSY;
1090 goto out;
1091 }
1092
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001093 while (retries) {
1094 retries--;
1095 ret = wl1271_chip_wakeup(wl);
1096 if (ret < 0)
1097 goto power_off;
1098
1099 ret = wl1271_boot(wl);
1100 if (ret < 0)
1101 goto power_off;
1102
1103 ret = wl1271_hw_init(wl);
1104 if (ret < 0)
1105 goto irq_disable;
1106
Eliad Peller71125ab2010-10-28 21:46:43 +02001107 booted = true;
1108 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001110irq_disable:
1111 wl1271_disable_interrupts(wl);
1112 mutex_unlock(&wl->mutex);
1113 /* Unlocking the mutex in the middle of handling is
1114 inherently unsafe. In this case we deem it safe to do,
1115 because we need to let any possibly pending IRQ out of
1116 the system (and while we are WL1271_STATE_OFF the IRQ
1117 work function will not do anything.) Also, any other
1118 possible concurrent operations will fail due to the
1119 current state, hence the wl1271 struct should be safe. */
1120 cancel_work_sync(&wl->irq_work);
1121 mutex_lock(&wl->mutex);
1122power_off:
1123 wl1271_power_off(wl);
1124 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125
Eliad Peller71125ab2010-10-28 21:46:43 +02001126 if (!booted) {
1127 wl1271_error("firmware boot failed despite %d retries",
1128 WL1271_BOOT_RETRIES);
1129 goto out;
1130 }
1131
1132 wl->vif = vif;
1133 wl->state = WL1271_STATE_ON;
1134 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1135
1136 /* update hw/fw version info in wiphy struct */
1137 wiphy->hw_version = wl->chip.id;
1138 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1139 sizeof(wiphy->fw_version));
1140
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001141 /*
1142 * Now we know if 11a is supported (info from the NVS), so disable
1143 * 11a channels if not supported
1144 */
1145 if (!wl->enable_11a)
1146 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1147
1148 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1149 wl->enable_11a ? "" : "not ");
1150
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001151out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001152 mutex_unlock(&wl->mutex);
1153
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001154 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001155 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001156
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001157 return ret;
1158}
1159
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001160static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162 int i;
1163
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001164 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001165
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001166 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001168 list_del(&wl->list);
1169
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170 WARN_ON(wl->state != WL1271_STATE_ON);
1171
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001172 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001173 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001174 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001175
Luciano Coelho08688d62010-07-08 17:50:07 +03001176 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001177 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1178 kfree(wl->scan.scanned_ch);
1179 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001180 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001181 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182 }
1183
1184 wl->state = WL1271_STATE_OFF;
1185
1186 wl1271_disable_interrupts(wl);
1187
1188 mutex_unlock(&wl->mutex);
1189
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001190 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001191 cancel_work_sync(&wl->irq_work);
1192 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001193 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001194 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195
1196 mutex_lock(&wl->mutex);
1197
1198 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001199 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200 wl1271_power_off(wl);
1201
1202 memset(wl->bssid, 0, ETH_ALEN);
1203 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1204 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001206 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001207 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208
1209 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001210 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1212 wl->tx_blocks_available = 0;
1213 wl->tx_results_count = 0;
1214 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001215 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001216 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217 wl->time_offset = 0;
1218 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001219 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1220 wl->sta_rate_set = 0;
1221 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001222 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001223 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001224 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001225 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001226
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227 for (i = 0; i < NUM_TX_QUEUES; i++)
1228 wl->tx_blocks_freed[i] = 0;
1229
1230 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001231
1232 kfree(wl->fw_status);
1233 wl->fw_status = NULL;
1234 kfree(wl->tx_res_if);
1235 wl->tx_res_if = NULL;
1236 kfree(wl->target_mem_map);
1237 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001238}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001239
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001240static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1241 struct ieee80211_vif *vif)
1242{
1243 struct wl1271 *wl = hw->priv;
1244
1245 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001246 /*
1247 * wl->vif can be null here if someone shuts down the interface
1248 * just when hardware recovery has been started.
1249 */
1250 if (wl->vif) {
1251 WARN_ON(wl->vif != vif);
1252 __wl1271_op_remove_interface(wl);
1253 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001254
Juuso Oikarinen67353292010-11-18 15:19:02 +02001255 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257}
1258
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001259static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1260{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001261 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001262
1263 /* combine requested filters with current filter config */
1264 filters = wl->filters | filters;
1265
1266 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1267
1268 if (filters & FIF_PROMISC_IN_BSS) {
1269 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1270 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1271 wl->rx_config |= CFG_BSSID_FILTER_EN;
1272 }
1273 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1274 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1275 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1276 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1277 }
1278 if (filters & FIF_OTHER_BSS) {
1279 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1280 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1281 }
1282 if (filters & FIF_CONTROL) {
1283 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1284 wl->rx_filter |= CFG_RX_CTL_EN;
1285 }
1286 if (filters & FIF_FCSFAIL) {
1287 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1288 wl->rx_filter |= CFG_RX_FCS_ERROR;
1289 }
1290}
1291
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001292static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001293{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001294 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001295 /* we need to use a dummy BSSID for now */
1296 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1297 0xad, 0xbe, 0xef };
1298
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001299 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1300
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001301 /* pass through frames from all BSS */
1302 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1303
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001304 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001305 if (ret < 0)
1306 goto out;
1307
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001308 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001309
1310out:
1311 return ret;
1312}
1313
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001314static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001315{
1316 int ret;
1317
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001318 /*
1319 * One of the side effects of the JOIN command is that is clears
1320 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1321 * to a WPA/WPA2 access point will therefore kill the data-path.
1322 * Currently there is no supported scenario for JOIN during
1323 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1324 * must be handled somehow.
1325 *
1326 */
1327 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1328 wl1271_info("JOIN while associated.");
1329
1330 if (set_assoc)
1331 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1332
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001333 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1334 if (ret < 0)
1335 goto out;
1336
1337 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1338
1339 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1340 goto out;
1341
1342 /*
1343 * The join command disable the keep-alive mode, shut down its process,
1344 * and also clear the template config, so we need to reset it all after
1345 * the join. The acx_aid starts the keep-alive process, and the order
1346 * of the commands below is relevant.
1347 */
1348 ret = wl1271_acx_keep_alive_mode(wl, true);
1349 if (ret < 0)
1350 goto out;
1351
1352 ret = wl1271_acx_aid(wl, wl->aid);
1353 if (ret < 0)
1354 goto out;
1355
1356 ret = wl1271_cmd_build_klv_null_data(wl);
1357 if (ret < 0)
1358 goto out;
1359
1360 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1361 ACX_KEEP_ALIVE_TPL_VALID);
1362 if (ret < 0)
1363 goto out;
1364
1365out:
1366 return ret;
1367}
1368
1369static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001370{
1371 int ret;
1372
1373 /* to stop listening to a channel, we disconnect */
1374 ret = wl1271_cmd_disconnect(wl);
1375 if (ret < 0)
1376 goto out;
1377
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001378 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001379 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001380
1381 /* stop filterting packets based on bssid */
1382 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001383
1384out:
1385 return ret;
1386}
1387
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001388static void wl1271_set_band_rate(struct wl1271 *wl)
1389{
1390 if (wl->band == IEEE80211_BAND_2GHZ)
1391 wl->basic_rate_set = wl->conf.tx.basic_rate;
1392 else
1393 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1394}
1395
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001396static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001397{
1398 int ret;
1399
1400 if (idle) {
1401 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1402 ret = wl1271_unjoin(wl);
1403 if (ret < 0)
1404 goto out;
1405 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001406 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001407 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001408 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001409 if (ret < 0)
1410 goto out;
1411 ret = wl1271_acx_keep_alive_config(
1412 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1413 ACX_KEEP_ALIVE_TPL_INVALID);
1414 if (ret < 0)
1415 goto out;
1416 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1417 } else {
1418 /* increment the session counter */
1419 wl->session_counter++;
1420 if (wl->session_counter >= SESSION_COUNTER_MAX)
1421 wl->session_counter = 0;
1422 ret = wl1271_dummy_join(wl);
1423 if (ret < 0)
1424 goto out;
1425 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1426 }
1427
1428out:
1429 return ret;
1430}
1431
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1433{
1434 struct wl1271 *wl = hw->priv;
1435 struct ieee80211_conf *conf = &hw->conf;
1436 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001437 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
1439 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1440
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001441 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1442 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 channel,
1444 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001445 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001446 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1447 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001449 /*
1450 * mac80211 will go to idle nearly immediately after transmitting some
1451 * frames, such as the deauth. To make sure those frames reach the air,
1452 * wait here until the TX queue is fully flushed.
1453 */
1454 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1455 (conf->flags & IEEE80211_CONF_IDLE))
1456 wl1271_tx_flush(wl);
1457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 mutex_lock(&wl->mutex);
1459
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001460 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1461 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001462 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001463 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001464
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001465 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1466
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 ret = wl1271_ps_elp_wakeup(wl, false);
1468 if (ret < 0)
1469 goto out;
1470
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001471 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001472 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1473 ((wl->band != conf->channel->band) ||
1474 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001475 wl->band = conf->channel->band;
1476 wl->channel = channel;
1477
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001478 if (!is_ap) {
1479 /*
1480 * FIXME: the mac80211 should really provide a fixed
1481 * rate to use here. for now, just use the smallest
1482 * possible rate for the band as a fixed rate for
1483 * association frames and other control messages.
1484 */
1485 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1486 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001487
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001488 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1489 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001490 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001491 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001492 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001493
1494 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1495 ret = wl1271_join(wl, false);
1496 if (ret < 0)
1497 wl1271_warning("cmd join on channel "
1498 "failed %d", ret);
1499 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001500 }
1501 }
1502
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001503 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1504 ret = wl1271_sta_handle_idle(wl,
1505 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001506 if (ret < 0)
1507 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 }
1509
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001510 /*
1511 * if mac80211 changes the PSM mode, make sure the mode is not
1512 * incorrectly changed after the pspoll failure active window.
1513 */
1514 if (changed & IEEE80211_CONF_CHANGE_PS)
1515 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1516
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001517 if (conf->flags & IEEE80211_CONF_PS &&
1518 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1519 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520
1521 /*
1522 * We enter PSM only if we're already associated.
1523 * If we're not, we'll enter it when joining an SSID,
1524 * through the bss_info_changed() hook.
1525 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001526 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001527 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001528 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001529 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001530 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001532 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001533 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001535 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001537 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001538 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001539 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540 }
1541
1542 if (conf->power_level != wl->power_level) {
1543 ret = wl1271_acx_tx_power(wl, conf->power_level);
1544 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001545 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546
1547 wl->power_level = conf->power_level;
1548 }
1549
1550out_sleep:
1551 wl1271_ps_elp_sleep(wl);
1552
1553out:
1554 mutex_unlock(&wl->mutex);
1555
1556 return ret;
1557}
1558
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001559struct wl1271_filter_params {
1560 bool enabled;
1561 int mc_list_length;
1562 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1563};
1564
Jiri Pirko22bedad2010-04-01 21:22:57 +00001565static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1566 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001567{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001569 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001570 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001571
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001572 if (unlikely(wl->state == WL1271_STATE_OFF))
1573 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001574
Juuso Oikarinen74441132009-10-13 12:47:53 +03001575 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001576 if (!fp) {
1577 wl1271_error("Out of memory setting filters.");
1578 return 0;
1579 }
1580
1581 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001582 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001583 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1584 fp->enabled = false;
1585 } else {
1586 fp->enabled = true;
1587 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001588 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001589 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001590 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001591 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001592 }
1593
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001594 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001595}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001597#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1598 FIF_ALLMULTI | \
1599 FIF_FCSFAIL | \
1600 FIF_BCN_PRBRESP_PROMISC | \
1601 FIF_CONTROL | \
1602 FIF_OTHER_BSS)
1603
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1605 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001606 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001608 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001610 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611
Arik Nemtsov7d057862010-10-16 19:25:35 +02001612 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1613 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001615 mutex_lock(&wl->mutex);
1616
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001617 *total &= WL1271_SUPPORTED_FILTERS;
1618 changed &= WL1271_SUPPORTED_FILTERS;
1619
1620 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001621 goto out;
1622
1623 ret = wl1271_ps_elp_wakeup(wl, false);
1624 if (ret < 0)
1625 goto out;
1626
Arik Nemtsov7d057862010-10-16 19:25:35 +02001627 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1628 if (*total & FIF_ALLMULTI)
1629 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1630 else if (fp)
1631 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1632 fp->mc_list,
1633 fp->mc_list_length);
1634 if (ret < 0)
1635 goto out_sleep;
1636 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001637
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001638 /* determine, whether supported filter values have changed */
1639 if (changed == 0)
1640 goto out_sleep;
1641
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001642 /* configure filters */
1643 wl->filters = *total;
1644 wl1271_configure_filters(wl, 0);
1645
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001646 /* apply configured filters */
1647 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1648 if (ret < 0)
1649 goto out_sleep;
1650
1651out_sleep:
1652 wl1271_ps_elp_sleep(wl);
1653
1654out:
1655 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001656 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657}
1658
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001659static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1660 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1661 u16 tx_seq_16)
1662{
1663 struct wl1271_ap_key *ap_key;
1664 int i;
1665
1666 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1667
1668 if (key_size > MAX_KEY_SIZE)
1669 return -EINVAL;
1670
1671 /*
1672 * Find next free entry in ap_keys. Also check we are not replacing
1673 * an existing key.
1674 */
1675 for (i = 0; i < MAX_NUM_KEYS; i++) {
1676 if (wl->recorded_ap_keys[i] == NULL)
1677 break;
1678
1679 if (wl->recorded_ap_keys[i]->id == id) {
1680 wl1271_warning("trying to record key replacement");
1681 return -EINVAL;
1682 }
1683 }
1684
1685 if (i == MAX_NUM_KEYS)
1686 return -EBUSY;
1687
1688 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1689 if (!ap_key)
1690 return -ENOMEM;
1691
1692 ap_key->id = id;
1693 ap_key->key_type = key_type;
1694 ap_key->key_size = key_size;
1695 memcpy(ap_key->key, key, key_size);
1696 ap_key->hlid = hlid;
1697 ap_key->tx_seq_32 = tx_seq_32;
1698 ap_key->tx_seq_16 = tx_seq_16;
1699
1700 wl->recorded_ap_keys[i] = ap_key;
1701 return 0;
1702}
1703
1704static void wl1271_free_ap_keys(struct wl1271 *wl)
1705{
1706 int i;
1707
1708 for (i = 0; i < MAX_NUM_KEYS; i++) {
1709 kfree(wl->recorded_ap_keys[i]);
1710 wl->recorded_ap_keys[i] = NULL;
1711 }
1712}
1713
1714static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1715{
1716 int i, ret = 0;
1717 struct wl1271_ap_key *key;
1718 bool wep_key_added = false;
1719
1720 for (i = 0; i < MAX_NUM_KEYS; i++) {
1721 if (wl->recorded_ap_keys[i] == NULL)
1722 break;
1723
1724 key = wl->recorded_ap_keys[i];
1725 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1726 key->id, key->key_type,
1727 key->key_size, key->key,
1728 key->hlid, key->tx_seq_32,
1729 key->tx_seq_16);
1730 if (ret < 0)
1731 goto out;
1732
1733 if (key->key_type == KEY_WEP)
1734 wep_key_added = true;
1735 }
1736
1737 if (wep_key_added) {
1738 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1739 if (ret < 0)
1740 goto out;
1741 }
1742
1743out:
1744 wl1271_free_ap_keys(wl);
1745 return ret;
1746}
1747
1748static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1749 u8 key_size, const u8 *key, u32 tx_seq_32,
1750 u16 tx_seq_16, struct ieee80211_sta *sta)
1751{
1752 int ret;
1753 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1754
1755 if (is_ap) {
1756 struct wl1271_station *wl_sta;
1757 u8 hlid;
1758
1759 if (sta) {
1760 wl_sta = (struct wl1271_station *)sta->drv_priv;
1761 hlid = wl_sta->hlid;
1762 } else {
1763 hlid = WL1271_AP_BROADCAST_HLID;
1764 }
1765
1766 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1767 /*
1768 * We do not support removing keys after AP shutdown.
1769 * Pretend we do to make mac80211 happy.
1770 */
1771 if (action != KEY_ADD_OR_REPLACE)
1772 return 0;
1773
1774 ret = wl1271_record_ap_key(wl, id,
1775 key_type, key_size,
1776 key, hlid, tx_seq_32,
1777 tx_seq_16);
1778 } else {
1779 ret = wl1271_cmd_set_ap_key(wl, action,
1780 id, key_type, key_size,
1781 key, hlid, tx_seq_32,
1782 tx_seq_16);
1783 }
1784
1785 if (ret < 0)
1786 return ret;
1787 } else {
1788 const u8 *addr;
1789 static const u8 bcast_addr[ETH_ALEN] = {
1790 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1791 };
1792
1793 addr = sta ? sta->addr : bcast_addr;
1794
1795 if (is_zero_ether_addr(addr)) {
1796 /* We dont support TX only encryption */
1797 return -EOPNOTSUPP;
1798 }
1799
1800 /* The wl1271 does not allow to remove unicast keys - they
1801 will be cleared automatically on next CMD_JOIN. Ignore the
1802 request silently, as we dont want the mac80211 to emit
1803 an error message. */
1804 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1805 return 0;
1806
1807 ret = wl1271_cmd_set_sta_key(wl, action,
1808 id, key_type, key_size,
1809 key, addr, tx_seq_32,
1810 tx_seq_16);
1811 if (ret < 0)
1812 return ret;
1813
1814 /* the default WEP key needs to be configured at least once */
1815 if (key_type == KEY_WEP) {
1816 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1817 wl->default_key);
1818 if (ret < 0)
1819 return ret;
1820 }
1821 }
1822
1823 return 0;
1824}
1825
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1827 struct ieee80211_vif *vif,
1828 struct ieee80211_sta *sta,
1829 struct ieee80211_key_conf *key_conf)
1830{
1831 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001833 u32 tx_seq_32 = 0;
1834 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835 u8 key_type;
1836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1838
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001839 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001841 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 key_conf->keylen, key_conf->flags);
1843 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1844
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001845 mutex_lock(&wl->mutex);
1846
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001847 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1848 ret = -EAGAIN;
1849 goto out_unlock;
1850 }
1851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852 ret = wl1271_ps_elp_wakeup(wl, false);
1853 if (ret < 0)
1854 goto out_unlock;
1855
Johannes Berg97359d12010-08-10 09:46:38 +02001856 switch (key_conf->cipher) {
1857 case WLAN_CIPHER_SUITE_WEP40:
1858 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 key_type = KEY_WEP;
1860
1861 key_conf->hw_key_idx = key_conf->keyidx;
1862 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001863 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001864 key_type = KEY_TKIP;
1865
1866 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001867 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1868 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001869 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001870 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 key_type = KEY_AES;
1872
1873 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001874 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1875 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001876 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001877 case WL1271_CIPHER_SUITE_GEM:
1878 key_type = KEY_GEM;
1879 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1880 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1881 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001883 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001884
1885 ret = -EOPNOTSUPP;
1886 goto out_sleep;
1887 }
1888
1889 switch (cmd) {
1890 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001891 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1892 key_conf->keyidx, key_type,
1893 key_conf->keylen, key_conf->key,
1894 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895 if (ret < 0) {
1896 wl1271_error("Could not add or replace key");
1897 goto out_sleep;
1898 }
1899 break;
1900
1901 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001902 ret = wl1271_set_key(wl, KEY_REMOVE,
1903 key_conf->keyidx, key_type,
1904 key_conf->keylen, key_conf->key,
1905 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 if (ret < 0) {
1907 wl1271_error("Could not remove key");
1908 goto out_sleep;
1909 }
1910 break;
1911
1912 default:
1913 wl1271_error("Unsupported key cmd 0x%x", cmd);
1914 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915 break;
1916 }
1917
1918out_sleep:
1919 wl1271_ps_elp_sleep(wl);
1920
1921out_unlock:
1922 mutex_unlock(&wl->mutex);
1923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924 return ret;
1925}
1926
1927static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001928 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 struct cfg80211_scan_request *req)
1930{
1931 struct wl1271 *wl = hw->priv;
1932 int ret;
1933 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001934 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935
1936 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1937
1938 if (req->n_ssids) {
1939 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001940 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 }
1942
1943 mutex_lock(&wl->mutex);
1944
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001945 if (wl->state == WL1271_STATE_OFF) {
1946 /*
1947 * We cannot return -EBUSY here because cfg80211 will expect
1948 * a call to ieee80211_scan_completed if we do - in this case
1949 * there won't be any call.
1950 */
1951 ret = -EAGAIN;
1952 goto out;
1953 }
1954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 ret = wl1271_ps_elp_wakeup(wl, false);
1956 if (ret < 0)
1957 goto out;
1958
Luciano Coelho5924f892010-08-04 03:46:22 +03001959 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960
1961 wl1271_ps_elp_sleep(wl);
1962
1963out:
1964 mutex_unlock(&wl->mutex);
1965
1966 return ret;
1967}
1968
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001969static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1970{
1971 struct wl1271 *wl = hw->priv;
1972 int ret = 0;
1973
1974 mutex_lock(&wl->mutex);
1975
1976 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1977 ret = -EAGAIN;
1978 goto out;
1979 }
1980
1981 ret = wl1271_ps_elp_wakeup(wl, false);
1982 if (ret < 0)
1983 goto out;
1984
1985 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1986 if (ret < 0)
1987 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1988
1989 wl1271_ps_elp_sleep(wl);
1990
1991out:
1992 mutex_unlock(&wl->mutex);
1993
1994 return ret;
1995}
1996
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1998{
1999 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002000 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001
2002 mutex_lock(&wl->mutex);
2003
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002004 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2005 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002006 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002007 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002008
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 ret = wl1271_ps_elp_wakeup(wl, false);
2010 if (ret < 0)
2011 goto out;
2012
2013 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2014 if (ret < 0)
2015 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2016
2017 wl1271_ps_elp_sleep(wl);
2018
2019out:
2020 mutex_unlock(&wl->mutex);
2021
2022 return ret;
2023}
2024
Arik Nemtsove78a2872010-10-16 19:07:21 +02002025static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002026 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002027{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002028 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002029
2030 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002031 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002032 if (ptr[0] == WLAN_EID_SSID) {
2033 wl->ssid_len = ptr[1];
2034 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002035 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002036 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002037 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002038 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002039
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002040 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002041 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002042}
2043
Arik Nemtsove78a2872010-10-16 19:07:21 +02002044static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2045 struct ieee80211_bss_conf *bss_conf,
2046 u32 changed)
2047{
2048 int ret = 0;
2049
2050 if (changed & BSS_CHANGED_ERP_SLOT) {
2051 if (bss_conf->use_short_slot)
2052 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2053 else
2054 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2055 if (ret < 0) {
2056 wl1271_warning("Set slot time failed %d", ret);
2057 goto out;
2058 }
2059 }
2060
2061 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2062 if (bss_conf->use_short_preamble)
2063 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2064 else
2065 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2066 }
2067
2068 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2069 if (bss_conf->use_cts_prot)
2070 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2071 else
2072 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2073 if (ret < 0) {
2074 wl1271_warning("Set ctsprotect failed %d", ret);
2075 goto out;
2076 }
2077 }
2078
2079out:
2080 return ret;
2081}
2082
2083static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2084 struct ieee80211_vif *vif,
2085 struct ieee80211_bss_conf *bss_conf,
2086 u32 changed)
2087{
2088 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2089 int ret = 0;
2090
2091 if ((changed & BSS_CHANGED_BEACON_INT)) {
2092 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2093 bss_conf->beacon_int);
2094
2095 wl->beacon_int = bss_conf->beacon_int;
2096 }
2097
2098 if ((changed & BSS_CHANGED_BEACON)) {
2099 struct ieee80211_hdr *hdr;
2100 int ieoffset = offsetof(struct ieee80211_mgmt,
2101 u.beacon.variable);
2102 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2103 u16 tmpl_id;
2104
2105 if (!beacon)
2106 goto out;
2107
2108 wl1271_debug(DEBUG_MASTER, "beacon updated");
2109
2110 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2111 if (ret < 0) {
2112 dev_kfree_skb(beacon);
2113 goto out;
2114 }
2115 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2116 CMD_TEMPL_BEACON;
2117 ret = wl1271_cmd_template_set(wl, tmpl_id,
2118 beacon->data,
2119 beacon->len, 0,
2120 wl1271_tx_min_rate_get(wl));
2121 if (ret < 0) {
2122 dev_kfree_skb(beacon);
2123 goto out;
2124 }
2125
2126 hdr = (struct ieee80211_hdr *) beacon->data;
2127 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2128 IEEE80211_STYPE_PROBE_RESP);
2129
2130 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2131 CMD_TEMPL_PROBE_RESPONSE;
2132 ret = wl1271_cmd_template_set(wl,
2133 tmpl_id,
2134 beacon->data,
2135 beacon->len, 0,
2136 wl1271_tx_min_rate_get(wl));
2137 dev_kfree_skb(beacon);
2138 if (ret < 0)
2139 goto out;
2140 }
2141
2142out:
2143 return ret;
2144}
2145
2146/* AP mode changes */
2147static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148 struct ieee80211_vif *vif,
2149 struct ieee80211_bss_conf *bss_conf,
2150 u32 changed)
2151{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002152 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153
Arik Nemtsove78a2872010-10-16 19:07:21 +02002154 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2155 u32 rates = bss_conf->basic_rates;
2156 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157
Arik Nemtsove78a2872010-10-16 19:07:21 +02002158 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2159 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2160 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2161 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162
Arik Nemtsove78a2872010-10-16 19:07:21 +02002163 /* update the AP management rate policy with the new rates */
2164 mgmt_rc.enabled_rates = wl->basic_rate_set;
2165 mgmt_rc.long_retry_limit = 10;
2166 mgmt_rc.short_retry_limit = 10;
2167 mgmt_rc.aflags = 0;
2168 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2169 ACX_TX_AP_MODE_MGMT_RATE);
2170 if (ret < 0) {
2171 wl1271_error("AP mgmt policy change failed %d", ret);
2172 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002173 }
2174 }
2175
Arik Nemtsove78a2872010-10-16 19:07:21 +02002176 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2177 if (ret < 0)
2178 goto out;
2179
2180 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2181 if (bss_conf->enable_beacon) {
2182 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2183 ret = wl1271_cmd_start_bss(wl);
2184 if (ret < 0)
2185 goto out;
2186
2187 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2188 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002189
2190 ret = wl1271_ap_init_hwenc(wl);
2191 if (ret < 0)
2192 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002193 }
2194 } else {
2195 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2196 ret = wl1271_cmd_stop_bss(wl);
2197 if (ret < 0)
2198 goto out;
2199
2200 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2201 wl1271_debug(DEBUG_AP, "stopped AP");
2202 }
2203 }
2204 }
2205
2206 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2207 if (ret < 0)
2208 goto out;
2209out:
2210 return;
2211}
2212
2213/* STA/IBSS mode changes */
2214static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2215 struct ieee80211_vif *vif,
2216 struct ieee80211_bss_conf *bss_conf,
2217 u32 changed)
2218{
2219 bool do_join = false, set_assoc = false;
2220 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2221 int ret;
2222 struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
2223
2224 if (is_ibss) {
2225 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2226 changed);
2227 if (ret < 0)
2228 goto out;
2229 }
2230
2231 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2232 do_join = true;
2233
2234 /* Need to update the SSID (for filtering etc) */
2235 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2236 do_join = true;
2237
2238 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002239 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2240 bss_conf->enable_beacon ? "enabled" : "disabled");
2241
2242 if (bss_conf->enable_beacon)
2243 wl->set_bss_type = BSS_TYPE_IBSS;
2244 else
2245 wl->set_bss_type = BSS_TYPE_STA_BSS;
2246 do_join = true;
2247 }
2248
Arik Nemtsove78a2872010-10-16 19:07:21 +02002249 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002250 bool enable = false;
2251 if (bss_conf->cqm_rssi_thold)
2252 enable = true;
2253 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2254 bss_conf->cqm_rssi_thold,
2255 bss_conf->cqm_rssi_hyst);
2256 if (ret < 0)
2257 goto out;
2258 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2259 }
2260
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002261 if ((changed & BSS_CHANGED_BSSID) &&
2262 /*
2263 * Now we know the correct bssid, so we send a new join command
2264 * and enable the BSSID filter
2265 */
2266 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002267 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002268
Arik Nemtsove78a2872010-10-16 19:07:21 +02002269 ret = wl1271_cmd_build_null_data(wl);
2270 if (ret < 0)
2271 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002272
Arik Nemtsove78a2872010-10-16 19:07:21 +02002273 ret = wl1271_build_qos_null_data(wl);
2274 if (ret < 0)
2275 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002276
Arik Nemtsove78a2872010-10-16 19:07:21 +02002277 /* filter out all packets not from this BSSID */
2278 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002279
Arik Nemtsove78a2872010-10-16 19:07:21 +02002280 /* Need to update the BSSID (for filtering etc) */
2281 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002282 }
2283
Arik Nemtsove78a2872010-10-16 19:07:21 +02002284 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002285 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002286 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002287 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002289 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002291 wl->ps_poll_failures = 0;
2292
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002293 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002294 * use basic rates from AP, and determine lowest rate
2295 * to use with control frames.
2296 */
2297 rates = bss_conf->basic_rates;
2298 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2299 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002300 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002301 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002302 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002303 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002304
2305 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002306 * with wl1271, we don't need to update the
2307 * beacon_int and dtim_period, because the firmware
2308 * updates it by itself when the first beacon is
2309 * received after a join.
2310 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2312 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002315 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002316 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002317 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002318 dev_kfree_skb(wl->probereq);
2319 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2320 ieoffset = offsetof(struct ieee80211_mgmt,
2321 u.probe_req.variable);
2322 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002323
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002324 /* enable the connection monitoring feature */
2325 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002326 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328
2329 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002330 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2331 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002332 enum wl1271_cmd_ps_mode mode;
2333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002335 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002336 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002337 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002339 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002341 } else {
2342 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002343 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002344 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002345 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002346
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002347 /* free probe-request template */
2348 dev_kfree_skb(wl->probereq);
2349 wl->probereq = NULL;
2350
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002351 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002352 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002353
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002354 /* revert back to minimum rates for the current band */
2355 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002356 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002357 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002358 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002359 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002360
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002361 /* disable connection monitor features */
2362 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002363
2364 /* Disable the keep-alive feature */
2365 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002366 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002367 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002368
2369 /* restore the bssid filter and go to dummy bssid */
2370 wl1271_unjoin(wl);
2371 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 }
2373 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002374
Arik Nemtsove78a2872010-10-16 19:07:21 +02002375 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2376 if (ret < 0)
2377 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378
Shahar Levi18357852010-10-13 16:09:41 +02002379 /*
2380 * Takes care of: New association with HT enable,
2381 * HT information change in beacon.
2382 */
2383 if (sta &&
2384 (changed & BSS_CHANGED_HT) &&
2385 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2386 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
2387 if (ret < 0) {
2388 wl1271_warning("Set ht cap true failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002389 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002390 }
2391 ret = wl1271_acx_set_ht_information(wl,
2392 bss_conf->ht_operation_mode);
2393 if (ret < 0) {
2394 wl1271_warning("Set ht information failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002395 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002396 }
2397 }
2398 /*
2399 * Takes care of: New association without HT,
2400 * Disassociation.
2401 */
2402 else if (sta && (changed & BSS_CHANGED_ASSOC)) {
2403 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
2404 if (ret < 0) {
2405 wl1271_warning("Set ht cap false failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002406 goto out;
Shahar Levi18357852010-10-13 16:09:41 +02002407 }
2408 }
2409
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002410 if (changed & BSS_CHANGED_ARP_FILTER) {
2411 __be32 addr = bss_conf->arp_addr_list[0];
2412 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2413
Eliad Pellerc5312772010-12-09 11:31:27 +02002414 if (bss_conf->arp_addr_cnt == 1 &&
2415 bss_conf->arp_filter_enabled) {
2416 /*
2417 * The template should have been configured only upon
2418 * association. however, it seems that the correct ip
2419 * isn't being set (when sending), so we have to
2420 * reconfigure the template upon every ip change.
2421 */
2422 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2423 if (ret < 0) {
2424 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002425 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002426 }
2427
2428 ret = wl1271_acx_arp_ip_filter(wl,
2429 (ACX_ARP_FILTER_ARP_FILTERING |
2430 ACX_ARP_FILTER_AUTO_ARP),
2431 addr);
2432 } else
2433 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002434
2435 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002436 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002437 }
2438
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002439 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002440 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002441 if (ret < 0) {
2442 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002443 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002444 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002445 }
2446
Arik Nemtsove78a2872010-10-16 19:07:21 +02002447out:
2448 return;
2449}
2450
2451static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2452 struct ieee80211_vif *vif,
2453 struct ieee80211_bss_conf *bss_conf,
2454 u32 changed)
2455{
2456 struct wl1271 *wl = hw->priv;
2457 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2458 int ret;
2459
2460 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2461 (int)changed);
2462
2463 mutex_lock(&wl->mutex);
2464
2465 if (unlikely(wl->state == WL1271_STATE_OFF))
2466 goto out;
2467
2468 ret = wl1271_ps_elp_wakeup(wl, false);
2469 if (ret < 0)
2470 goto out;
2471
2472 if (is_ap)
2473 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2474 else
2475 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2476
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477 wl1271_ps_elp_sleep(wl);
2478
2479out:
2480 mutex_unlock(&wl->mutex);
2481}
2482
Kalle Valoc6999d82010-02-18 13:25:41 +02002483static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2484 const struct ieee80211_tx_queue_params *params)
2485{
2486 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002487 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002488 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002489
2490 mutex_lock(&wl->mutex);
2491
2492 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2493
Kalle Valo4695dc92010-03-18 12:26:38 +02002494 if (params->uapsd)
2495 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2496 else
2497 ps_scheme = CONF_PS_SCHEME_LEGACY;
2498
Arik Nemtsov488fc542010-10-16 20:33:45 +02002499 if (wl->state == WL1271_STATE_OFF) {
2500 /*
2501 * If the state is off, the parameters will be recorded and
2502 * configured on init. This happens in AP-mode.
2503 */
2504 struct conf_tx_ac_category *conf_ac =
2505 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2506 struct conf_tx_tid *conf_tid =
2507 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2508
2509 conf_ac->ac = wl1271_tx_get_queue(queue);
2510 conf_ac->cw_min = (u8)params->cw_min;
2511 conf_ac->cw_max = params->cw_max;
2512 conf_ac->aifsn = params->aifs;
2513 conf_ac->tx_op_limit = params->txop << 5;
2514
2515 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2516 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2517 conf_tid->tsid = wl1271_tx_get_queue(queue);
2518 conf_tid->ps_scheme = ps_scheme;
2519 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2520 conf_tid->apsd_conf[0] = 0;
2521 conf_tid->apsd_conf[1] = 0;
2522 } else {
2523 ret = wl1271_ps_elp_wakeup(wl, false);
2524 if (ret < 0)
2525 goto out;
2526
2527 /*
2528 * the txop is confed in units of 32us by the mac80211,
2529 * we need us
2530 */
2531 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2532 params->cw_min, params->cw_max,
2533 params->aifs, params->txop << 5);
2534 if (ret < 0)
2535 goto out_sleep;
2536
2537 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2538 CONF_CHANNEL_TYPE_EDCF,
2539 wl1271_tx_get_queue(queue),
2540 ps_scheme, CONF_ACK_POLICY_LEGACY,
2541 0, 0);
2542 if (ret < 0)
2543 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002544
2545out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002546 wl1271_ps_elp_sleep(wl);
2547 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002548
2549out:
2550 mutex_unlock(&wl->mutex);
2551
2552 return ret;
2553}
2554
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002555static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2556{
2557
2558 struct wl1271 *wl = hw->priv;
2559 u64 mactime = ULLONG_MAX;
2560 int ret;
2561
2562 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2563
2564 mutex_lock(&wl->mutex);
2565
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002566 if (unlikely(wl->state == WL1271_STATE_OFF))
2567 goto out;
2568
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002569 ret = wl1271_ps_elp_wakeup(wl, false);
2570 if (ret < 0)
2571 goto out;
2572
2573 ret = wl1271_acx_tsf_info(wl, &mactime);
2574 if (ret < 0)
2575 goto out_sleep;
2576
2577out_sleep:
2578 wl1271_ps_elp_sleep(wl);
2579
2580out:
2581 mutex_unlock(&wl->mutex);
2582 return mactime;
2583}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584
John W. Linvilleece550d2010-07-28 16:41:06 -04002585static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2586 struct survey_info *survey)
2587{
2588 struct wl1271 *wl = hw->priv;
2589 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002590
John W. Linvilleece550d2010-07-28 16:41:06 -04002591 if (idx != 0)
2592 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002593
John W. Linvilleece550d2010-07-28 16:41:06 -04002594 survey->channel = conf->channel;
2595 survey->filled = SURVEY_INFO_NOISE_DBM;
2596 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002597
John W. Linvilleece550d2010-07-28 16:41:06 -04002598 return 0;
2599}
2600
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002601static int wl1271_allocate_hlid(struct wl1271 *wl,
2602 struct ieee80211_sta *sta,
2603 u8 *hlid)
2604{
2605 struct wl1271_station *wl_sta;
2606 int id;
2607
2608 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2609 if (id >= AP_MAX_STATIONS) {
2610 wl1271_warning("could not allocate HLID - too much stations");
2611 return -EBUSY;
2612 }
2613
2614 wl_sta = (struct wl1271_station *)sta->drv_priv;
2615
2616 __set_bit(id, wl->ap_hlid_map);
2617 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2618 *hlid = wl_sta->hlid;
2619 return 0;
2620}
2621
2622static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2623{
2624 int id = hlid - WL1271_AP_STA_HLID_START;
2625
2626 __clear_bit(id, wl->ap_hlid_map);
2627}
2628
2629static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2630 struct ieee80211_vif *vif,
2631 struct ieee80211_sta *sta)
2632{
2633 struct wl1271 *wl = hw->priv;
2634 int ret = 0;
2635 u8 hlid;
2636
2637 mutex_lock(&wl->mutex);
2638
2639 if (unlikely(wl->state == WL1271_STATE_OFF))
2640 goto out;
2641
2642 if (wl->bss_type != BSS_TYPE_AP_BSS)
2643 goto out;
2644
2645 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2646
2647 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2648 if (ret < 0)
2649 goto out;
2650
2651 ret = wl1271_ps_elp_wakeup(wl, false);
2652 if (ret < 0)
2653 goto out;
2654
2655 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2656 if (ret < 0)
2657 goto out_sleep;
2658
2659out_sleep:
2660 wl1271_ps_elp_sleep(wl);
2661
2662out:
2663 mutex_unlock(&wl->mutex);
2664 return ret;
2665}
2666
2667static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2668 struct ieee80211_vif *vif,
2669 struct ieee80211_sta *sta)
2670{
2671 struct wl1271 *wl = hw->priv;
2672 struct wl1271_station *wl_sta;
2673 int ret = 0, id;
2674
2675 mutex_lock(&wl->mutex);
2676
2677 if (unlikely(wl->state == WL1271_STATE_OFF))
2678 goto out;
2679
2680 if (wl->bss_type != BSS_TYPE_AP_BSS)
2681 goto out;
2682
2683 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2684
2685 wl_sta = (struct wl1271_station *)sta->drv_priv;
2686 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2687 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2688 goto out;
2689
2690 ret = wl1271_ps_elp_wakeup(wl, false);
2691 if (ret < 0)
2692 goto out;
2693
2694 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2695 if (ret < 0)
2696 goto out_sleep;
2697
2698 wl1271_free_hlid(wl, wl_sta->hlid);
2699
2700out_sleep:
2701 wl1271_ps_elp_sleep(wl);
2702
2703out:
2704 mutex_unlock(&wl->mutex);
2705 return ret;
2706}
2707
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708/* can't be const, mac80211 writes to this */
2709static struct ieee80211_rate wl1271_rates[] = {
2710 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002711 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2712 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002714 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2715 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2717 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002718 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2719 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2721 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002722 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2723 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2725 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002726 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2727 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002729 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2730 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002732 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2733 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002735 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2736 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002738 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2739 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002741 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2742 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002744 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2745 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002746 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002747 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2748 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749};
2750
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002751/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002753 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002754 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002755 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2756 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2757 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002758 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002759 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2760 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2761 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002762 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002763 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2764 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2765 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766};
2767
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002768/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002769static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002770 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002771 7, /* CONF_HW_RXTX_RATE_MCS7 */
2772 6, /* CONF_HW_RXTX_RATE_MCS6 */
2773 5, /* CONF_HW_RXTX_RATE_MCS5 */
2774 4, /* CONF_HW_RXTX_RATE_MCS4 */
2775 3, /* CONF_HW_RXTX_RATE_MCS3 */
2776 2, /* CONF_HW_RXTX_RATE_MCS2 */
2777 1, /* CONF_HW_RXTX_RATE_MCS1 */
2778 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002779
2780 11, /* CONF_HW_RXTX_RATE_54 */
2781 10, /* CONF_HW_RXTX_RATE_48 */
2782 9, /* CONF_HW_RXTX_RATE_36 */
2783 8, /* CONF_HW_RXTX_RATE_24 */
2784
2785 /* TI-specific rate */
2786 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2787
2788 7, /* CONF_HW_RXTX_RATE_18 */
2789 6, /* CONF_HW_RXTX_RATE_12 */
2790 3, /* CONF_HW_RXTX_RATE_11 */
2791 5, /* CONF_HW_RXTX_RATE_9 */
2792 4, /* CONF_HW_RXTX_RATE_6 */
2793 2, /* CONF_HW_RXTX_RATE_5_5 */
2794 1, /* CONF_HW_RXTX_RATE_2 */
2795 0 /* CONF_HW_RXTX_RATE_1 */
2796};
2797
Shahar Levie8b03a22010-10-13 16:09:39 +02002798/* 11n STA capabilities */
2799#define HW_RX_HIGHEST_RATE 72
2800
Shahar Levi00d20102010-11-08 11:20:10 +00002801#ifdef CONFIG_WL12XX_HT
2802#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002803 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2804 .ht_supported = true, \
2805 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2806 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2807 .mcs = { \
2808 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2809 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2810 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2811 }, \
2812}
Shahar Levi18357852010-10-13 16:09:41 +02002813#else
Shahar Levi00d20102010-11-08 11:20:10 +00002814#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002815 .ht_supported = false, \
2816}
2817#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002818
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819/* can't be const, mac80211 writes to this */
2820static struct ieee80211_supported_band wl1271_band_2ghz = {
2821 .channels = wl1271_channels,
2822 .n_channels = ARRAY_SIZE(wl1271_channels),
2823 .bitrates = wl1271_rates,
2824 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002825 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826};
2827
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002828/* 5 GHz data rates for WL1273 */
2829static struct ieee80211_rate wl1271_rates_5ghz[] = {
2830 { .bitrate = 60,
2831 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2832 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2833 { .bitrate = 90,
2834 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2835 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2836 { .bitrate = 120,
2837 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2838 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2839 { .bitrate = 180,
2840 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2841 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2842 { .bitrate = 240,
2843 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2844 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2845 { .bitrate = 360,
2846 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2847 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2848 { .bitrate = 480,
2849 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2850 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2851 { .bitrate = 540,
2852 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2853 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2854};
2855
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002856/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002857static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002858 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002859 { .hw_value = 8, .center_freq = 5040},
2860 { .hw_value = 9, .center_freq = 5045},
2861 { .hw_value = 11, .center_freq = 5055},
2862 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002863 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002864 { .hw_value = 34, .center_freq = 5170},
2865 { .hw_value = 36, .center_freq = 5180},
2866 { .hw_value = 38, .center_freq = 5190},
2867 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002868 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002869 { .hw_value = 44, .center_freq = 5220},
2870 { .hw_value = 46, .center_freq = 5230},
2871 { .hw_value = 48, .center_freq = 5240},
2872 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002873 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002874 { .hw_value = 60, .center_freq = 5300},
2875 { .hw_value = 64, .center_freq = 5320},
2876 { .hw_value = 100, .center_freq = 5500},
2877 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002878 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002879 { .hw_value = 112, .center_freq = 5560},
2880 { .hw_value = 116, .center_freq = 5580},
2881 { .hw_value = 120, .center_freq = 5600},
2882 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002883 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002884 { .hw_value = 132, .center_freq = 5660},
2885 { .hw_value = 136, .center_freq = 5680},
2886 { .hw_value = 140, .center_freq = 5700},
2887 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002888 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002889 { .hw_value = 157, .center_freq = 5785},
2890 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002891 { .hw_value = 165, .center_freq = 5825},
2892};
2893
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002894/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002895static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002896 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002897 7, /* CONF_HW_RXTX_RATE_MCS7 */
2898 6, /* CONF_HW_RXTX_RATE_MCS6 */
2899 5, /* CONF_HW_RXTX_RATE_MCS5 */
2900 4, /* CONF_HW_RXTX_RATE_MCS4 */
2901 3, /* CONF_HW_RXTX_RATE_MCS3 */
2902 2, /* CONF_HW_RXTX_RATE_MCS2 */
2903 1, /* CONF_HW_RXTX_RATE_MCS1 */
2904 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002905
2906 7, /* CONF_HW_RXTX_RATE_54 */
2907 6, /* CONF_HW_RXTX_RATE_48 */
2908 5, /* CONF_HW_RXTX_RATE_36 */
2909 4, /* CONF_HW_RXTX_RATE_24 */
2910
2911 /* TI-specific rate */
2912 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2913
2914 3, /* CONF_HW_RXTX_RATE_18 */
2915 2, /* CONF_HW_RXTX_RATE_12 */
2916 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2917 1, /* CONF_HW_RXTX_RATE_9 */
2918 0, /* CONF_HW_RXTX_RATE_6 */
2919 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2920 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2921 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2922};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002923
2924static struct ieee80211_supported_band wl1271_band_5ghz = {
2925 .channels = wl1271_channels_5ghz,
2926 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2927 .bitrates = wl1271_rates_5ghz,
2928 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002929 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002930};
2931
Tobias Klausera0ea9492010-05-20 10:38:11 +02002932static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002933 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2934 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2935};
2936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937static const struct ieee80211_ops wl1271_ops = {
2938 .start = wl1271_op_start,
2939 .stop = wl1271_op_stop,
2940 .add_interface = wl1271_op_add_interface,
2941 .remove_interface = wl1271_op_remove_interface,
2942 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002943 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 .configure_filter = wl1271_op_configure_filter,
2945 .tx = wl1271_op_tx,
2946 .set_key = wl1271_op_set_key,
2947 .hw_scan = wl1271_op_hw_scan,
2948 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002949 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002951 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002952 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002953 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002954 .sta_add = wl1271_op_sta_add,
2955 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002956 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957};
2958
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002959
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002960u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002961{
2962 u8 idx;
2963
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002964 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002965
2966 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2967 wl1271_error("Illegal RX rate from HW: %d", rate);
2968 return 0;
2969 }
2970
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002971 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002972 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2973 wl1271_error("Unsupported RX rate from HW: %d", rate);
2974 return 0;
2975 }
2976
2977 return idx;
2978}
2979
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002980static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2981 struct device_attribute *attr,
2982 char *buf)
2983{
2984 struct wl1271 *wl = dev_get_drvdata(dev);
2985 ssize_t len;
2986
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002987 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002988
2989 mutex_lock(&wl->mutex);
2990 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2991 wl->sg_enabled);
2992 mutex_unlock(&wl->mutex);
2993
2994 return len;
2995
2996}
2997
2998static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2999 struct device_attribute *attr,
3000 const char *buf, size_t count)
3001{
3002 struct wl1271 *wl = dev_get_drvdata(dev);
3003 unsigned long res;
3004 int ret;
3005
3006 ret = strict_strtoul(buf, 10, &res);
3007
3008 if (ret < 0) {
3009 wl1271_warning("incorrect value written to bt_coex_mode");
3010 return count;
3011 }
3012
3013 mutex_lock(&wl->mutex);
3014
3015 res = !!res;
3016
3017 if (res == wl->sg_enabled)
3018 goto out;
3019
3020 wl->sg_enabled = res;
3021
3022 if (wl->state == WL1271_STATE_OFF)
3023 goto out;
3024
3025 ret = wl1271_ps_elp_wakeup(wl, false);
3026 if (ret < 0)
3027 goto out;
3028
3029 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3030 wl1271_ps_elp_sleep(wl);
3031
3032 out:
3033 mutex_unlock(&wl->mutex);
3034 return count;
3035}
3036
3037static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3038 wl1271_sysfs_show_bt_coex_state,
3039 wl1271_sysfs_store_bt_coex_state);
3040
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003041static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3042 struct device_attribute *attr,
3043 char *buf)
3044{
3045 struct wl1271 *wl = dev_get_drvdata(dev);
3046 ssize_t len;
3047
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003048 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003049
3050 mutex_lock(&wl->mutex);
3051 if (wl->hw_pg_ver >= 0)
3052 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3053 else
3054 len = snprintf(buf, len, "n/a\n");
3055 mutex_unlock(&wl->mutex);
3056
3057 return len;
3058}
3059
3060static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3061 wl1271_sysfs_show_hw_pg_ver, NULL);
3062
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003063int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003064{
3065 int ret;
3066
3067 if (wl->mac80211_registered)
3068 return 0;
3069
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003070 ret = wl1271_fetch_nvs(wl);
3071 if (ret == 0) {
3072 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3073
3074 wl->mac_addr[0] = nvs_ptr[11];
3075 wl->mac_addr[1] = nvs_ptr[10];
3076 wl->mac_addr[2] = nvs_ptr[6];
3077 wl->mac_addr[3] = nvs_ptr[5];
3078 wl->mac_addr[4] = nvs_ptr[4];
3079 wl->mac_addr[5] = nvs_ptr[3];
3080 }
3081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003082 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3083
3084 ret = ieee80211_register_hw(wl->hw);
3085 if (ret < 0) {
3086 wl1271_error("unable to register mac80211 hw: %d", ret);
3087 return ret;
3088 }
3089
3090 wl->mac80211_registered = true;
3091
Eliad Pellerd60080a2010-11-24 12:53:16 +02003092 wl1271_debugfs_init(wl);
3093
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003094 register_netdevice_notifier(&wl1271_dev_notifier);
3095
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003096 wl1271_notice("loaded");
3097
3098 return 0;
3099}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003100EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003101
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003102void wl1271_unregister_hw(struct wl1271 *wl)
3103{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003104 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003105 ieee80211_unregister_hw(wl->hw);
3106 wl->mac80211_registered = false;
3107
3108}
3109EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3110
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003111int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003113 static const u32 cipher_suites[] = {
3114 WLAN_CIPHER_SUITE_WEP40,
3115 WLAN_CIPHER_SUITE_WEP104,
3116 WLAN_CIPHER_SUITE_TKIP,
3117 WLAN_CIPHER_SUITE_CCMP,
3118 WL1271_CIPHER_SUITE_GEM,
3119 };
3120
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003121 /* The tx descriptor buffer and the TKIP space. */
3122 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3123 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003124
3125 /* unit us */
3126 /* FIXME: find a proper value */
3127 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003128 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003129
3130 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003131 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003132 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003133 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003134 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003135 IEEE80211_HW_CONNECTION_MONITOR |
3136 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003138 wl->hw->wiphy->cipher_suites = cipher_suites;
3139 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3140
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003141 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003142 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003144 /*
3145 * Maximum length of elements in scanning probe request templates
3146 * should be the maximum length possible for a template, without
3147 * the IEEE80211 header of the template
3148 */
3149 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3150 sizeof(struct ieee80211_header);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003151 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +03003152 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003153
Kalle Valo12bd8942010-03-18 12:26:33 +02003154 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003155 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003156
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003157 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3158
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003159 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003160
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003161 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3162
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 return 0;
3164}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003165EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003166
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003167#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003168
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003169struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003170{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003171 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003172 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003173 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003174 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003175 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003176
3177 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3178 if (!hw) {
3179 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003180 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003181 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003182 }
3183
Julia Lawall929ebd32010-05-15 23:16:39 +02003184 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003185 if (!plat_dev) {
3186 wl1271_error("could not allocate platform_device");
3187 ret = -ENOMEM;
3188 goto err_plat_alloc;
3189 }
3190
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003191 wl = hw->priv;
3192 memset(wl, 0, sizeof(*wl));
3193
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003194 INIT_LIST_HEAD(&wl->list);
3195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003197 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003199 for (i = 0; i < NUM_TX_QUEUES; i++)
3200 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003201
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003202 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003203 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003204 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3205 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3206 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3207 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003209 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003210 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003212 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3213 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003214 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003215 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003216 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003217 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003218 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3219 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003220 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003221 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003222 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003223 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003224 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003225 wl->bss_type = MAX_BSS_TYPE;
3226 wl->set_bss_type = MAX_BSS_TYPE;
3227 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003229 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003230 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231 wl->tx_frames[i] = NULL;
3232
3233 spin_lock_init(&wl->wl_lock);
3234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 wl->state = WL1271_STATE_OFF;
3236 mutex_init(&wl->mutex);
3237
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003238 /* Apply default driver configuration. */
3239 wl1271_conf_init(wl);
3240
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003241 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3242 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3243 if (!wl->aggr_buf) {
3244 ret = -ENOMEM;
3245 goto err_hw;
3246 }
3247
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003248 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003249 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003250 if (ret) {
3251 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003252 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003253 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003254 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003255
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003256 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003257 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003258 if (ret < 0) {
3259 wl1271_error("failed to create sysfs file bt_coex_state");
3260 goto err_platform;
3261 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003262
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003263 /* Create sysfs file to get HW PG version */
3264 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3265 if (ret < 0) {
3266 wl1271_error("failed to create sysfs file hw_pg_ver");
3267 goto err_bt_coex_state;
3268 }
3269
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003270 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003271
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003272err_bt_coex_state:
3273 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3274
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003275err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003276 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003277
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003278err_aggr:
3279 free_pages((unsigned long)wl->aggr_buf, order);
3280
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003281err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003282 wl1271_debugfs_exit(wl);
3283 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003284
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003285err_plat_alloc:
3286 ieee80211_free_hw(hw);
3287
3288err_hw_alloc:
3289
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003290 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003291}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003292EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003293
3294int wl1271_free_hw(struct wl1271 *wl)
3295{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003296 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003297 free_pages((unsigned long)wl->aggr_buf,
3298 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003299 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003300
3301 wl1271_debugfs_exit(wl);
3302
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003303 vfree(wl->fw);
3304 wl->fw = NULL;
3305 kfree(wl->nvs);
3306 wl->nvs = NULL;
3307
3308 kfree(wl->fw_status);
3309 kfree(wl->tx_res_if);
3310
3311 ieee80211_free_hw(wl->hw);
3312
3313 return 0;
3314}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003315EXPORT_SYMBOL_GPL(wl1271_free_hw);
3316
Eliad Peller17c17552010-12-12 12:15:35 +02003317u32 wl12xx_debug_level;
3318EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3319module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3320MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3321
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003322MODULE_LICENSE("GPL");
3323MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3324MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");