blob: 2192e4cf62f459496d7e40df9d680b0094f842d7 [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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-04-01 21:22:57 +00001589 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001590 fp->mc_list_length++;
Jiri Pirko22bedad32010-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;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002222 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002223
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
Eliad Pellerfa287b82010-12-26 09:27:50 +01002269 if (!is_zero_ether_addr(wl->bssid)) {
2270 ret = wl1271_cmd_build_null_data(wl);
2271 if (ret < 0)
2272 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002273
Eliad Pellerfa287b82010-12-26 09:27:50 +01002274 ret = wl1271_build_qos_null_data(wl);
2275 if (ret < 0)
2276 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002277
Eliad Pellerfa287b82010-12-26 09:27:50 +01002278 /* filter out all packets not from this BSSID */
2279 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002280
Eliad Pellerfa287b82010-12-26 09:27:50 +01002281 /* Need to update the BSSID (for filtering etc) */
2282 do_join = true;
2283 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002284 }
2285
Arik Nemtsove78a2872010-10-16 19:07:21 +02002286 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002288 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002289 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002291 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002293 wl->ps_poll_failures = 0;
2294
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002295 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002296 * use basic rates from AP, and determine lowest rate
2297 * to use with control frames.
2298 */
2299 rates = bss_conf->basic_rates;
2300 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2301 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002302 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002303 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002304 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002305 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002306
2307 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002308 * with wl1271, we don't need to update the
2309 * beacon_int and dtim_period, because the firmware
2310 * updates it by itself when the first beacon is
2311 * received after a join.
2312 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2314 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002315 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002317 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002318 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002319 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002320 dev_kfree_skb(wl->probereq);
2321 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2322 ieoffset = offsetof(struct ieee80211_mgmt,
2323 u.probe_req.variable);
2324 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002325
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002326 /* enable the connection monitoring feature */
2327 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002329 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330
2331 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002332 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2333 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002334 enum wl1271_cmd_ps_mode mode;
2335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002337 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002338 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002339 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002343 } else {
2344 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002345 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002346 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002347 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002348
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002349 /* free probe-request template */
2350 dev_kfree_skb(wl->probereq);
2351 wl->probereq = NULL;
2352
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002353 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002354 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002355
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002356 /* revert back to minimum rates for the current band */
2357 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002358 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002359 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002360 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002361 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002362
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002363 /* disable connection monitor features */
2364 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002365
2366 /* Disable the keep-alive feature */
2367 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002368 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002369 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002370
2371 /* restore the bssid filter and go to dummy bssid */
2372 wl1271_unjoin(wl);
2373 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 }
2375 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002376
Arik Nemtsove78a2872010-10-16 19:07:21 +02002377 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2378 if (ret < 0)
2379 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002381 rcu_read_lock();
2382 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2383 if (sta) {
2384 /* handle new association with HT and HT information change */
2385 if ((changed & BSS_CHANGED_HT) &&
2386 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2387 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2388 true);
2389 if (ret < 0) {
2390 wl1271_warning("Set ht cap true failed %d",
2391 ret);
2392 rcu_read_unlock();
2393 goto out;
2394 }
Shahar Levi18357852010-10-13 16:09:41 +02002395 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002396 bss_conf->ht_operation_mode);
2397 if (ret < 0) {
2398 wl1271_warning("Set ht information failed %d",
2399 ret);
2400 rcu_read_unlock();
2401 goto out;
2402 }
2403 }
2404 /* handle new association without HT and disassociation */
2405 else if (changed & BSS_CHANGED_ASSOC) {
2406 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2407 false);
2408 if (ret < 0) {
2409 wl1271_warning("Set ht cap false failed %d",
2410 ret);
2411 rcu_read_unlock();
2412 goto out;
2413 }
Shahar Levi18357852010-10-13 16:09:41 +02002414 }
2415 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002416 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002417
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002418 if (changed & BSS_CHANGED_ARP_FILTER) {
2419 __be32 addr = bss_conf->arp_addr_list[0];
2420 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2421
Eliad Pellerc5312772010-12-09 11:31:27 +02002422 if (bss_conf->arp_addr_cnt == 1 &&
2423 bss_conf->arp_filter_enabled) {
2424 /*
2425 * The template should have been configured only upon
2426 * association. however, it seems that the correct ip
2427 * isn't being set (when sending), so we have to
2428 * reconfigure the template upon every ip change.
2429 */
2430 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2431 if (ret < 0) {
2432 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002433 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002434 }
2435
2436 ret = wl1271_acx_arp_ip_filter(wl,
2437 (ACX_ARP_FILTER_ARP_FILTERING |
2438 ACX_ARP_FILTER_AUTO_ARP),
2439 addr);
2440 } else
2441 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002442
2443 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002445 }
2446
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002447 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002448 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002449 if (ret < 0) {
2450 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002451 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002452 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002453 }
2454
Arik Nemtsove78a2872010-10-16 19:07:21 +02002455out:
2456 return;
2457}
2458
2459static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2460 struct ieee80211_vif *vif,
2461 struct ieee80211_bss_conf *bss_conf,
2462 u32 changed)
2463{
2464 struct wl1271 *wl = hw->priv;
2465 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2466 int ret;
2467
2468 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2469 (int)changed);
2470
2471 mutex_lock(&wl->mutex);
2472
2473 if (unlikely(wl->state == WL1271_STATE_OFF))
2474 goto out;
2475
2476 ret = wl1271_ps_elp_wakeup(wl, false);
2477 if (ret < 0)
2478 goto out;
2479
2480 if (is_ap)
2481 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2482 else
2483 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485 wl1271_ps_elp_sleep(wl);
2486
2487out:
2488 mutex_unlock(&wl->mutex);
2489}
2490
Kalle Valoc6999d82010-02-18 13:25:41 +02002491static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2492 const struct ieee80211_tx_queue_params *params)
2493{
2494 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002495 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002496 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002497
2498 mutex_lock(&wl->mutex);
2499
2500 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2501
Kalle Valo4695dc92010-03-18 12:26:38 +02002502 if (params->uapsd)
2503 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2504 else
2505 ps_scheme = CONF_PS_SCHEME_LEGACY;
2506
Arik Nemtsov488fc542010-10-16 20:33:45 +02002507 if (wl->state == WL1271_STATE_OFF) {
2508 /*
2509 * If the state is off, the parameters will be recorded and
2510 * configured on init. This happens in AP-mode.
2511 */
2512 struct conf_tx_ac_category *conf_ac =
2513 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2514 struct conf_tx_tid *conf_tid =
2515 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2516
2517 conf_ac->ac = wl1271_tx_get_queue(queue);
2518 conf_ac->cw_min = (u8)params->cw_min;
2519 conf_ac->cw_max = params->cw_max;
2520 conf_ac->aifsn = params->aifs;
2521 conf_ac->tx_op_limit = params->txop << 5;
2522
2523 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2524 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2525 conf_tid->tsid = wl1271_tx_get_queue(queue);
2526 conf_tid->ps_scheme = ps_scheme;
2527 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2528 conf_tid->apsd_conf[0] = 0;
2529 conf_tid->apsd_conf[1] = 0;
2530 } else {
2531 ret = wl1271_ps_elp_wakeup(wl, false);
2532 if (ret < 0)
2533 goto out;
2534
2535 /*
2536 * the txop is confed in units of 32us by the mac80211,
2537 * we need us
2538 */
2539 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2540 params->cw_min, params->cw_max,
2541 params->aifs, params->txop << 5);
2542 if (ret < 0)
2543 goto out_sleep;
2544
2545 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2546 CONF_CHANNEL_TYPE_EDCF,
2547 wl1271_tx_get_queue(queue),
2548 ps_scheme, CONF_ACK_POLICY_LEGACY,
2549 0, 0);
2550 if (ret < 0)
2551 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002552
2553out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002554 wl1271_ps_elp_sleep(wl);
2555 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002556
2557out:
2558 mutex_unlock(&wl->mutex);
2559
2560 return ret;
2561}
2562
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002563static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2564{
2565
2566 struct wl1271 *wl = hw->priv;
2567 u64 mactime = ULLONG_MAX;
2568 int ret;
2569
2570 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2571
2572 mutex_lock(&wl->mutex);
2573
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002574 if (unlikely(wl->state == WL1271_STATE_OFF))
2575 goto out;
2576
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002577 ret = wl1271_ps_elp_wakeup(wl, false);
2578 if (ret < 0)
2579 goto out;
2580
2581 ret = wl1271_acx_tsf_info(wl, &mactime);
2582 if (ret < 0)
2583 goto out_sleep;
2584
2585out_sleep:
2586 wl1271_ps_elp_sleep(wl);
2587
2588out:
2589 mutex_unlock(&wl->mutex);
2590 return mactime;
2591}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592
John W. Linvilleece550d2010-07-28 16:41:06 -04002593static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2594 struct survey_info *survey)
2595{
2596 struct wl1271 *wl = hw->priv;
2597 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002598
John W. Linvilleece550d2010-07-28 16:41:06 -04002599 if (idx != 0)
2600 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002601
John W. Linvilleece550d2010-07-28 16:41:06 -04002602 survey->channel = conf->channel;
2603 survey->filled = SURVEY_INFO_NOISE_DBM;
2604 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002605
John W. Linvilleece550d2010-07-28 16:41:06 -04002606 return 0;
2607}
2608
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002609static int wl1271_allocate_hlid(struct wl1271 *wl,
2610 struct ieee80211_sta *sta,
2611 u8 *hlid)
2612{
2613 struct wl1271_station *wl_sta;
2614 int id;
2615
2616 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2617 if (id >= AP_MAX_STATIONS) {
2618 wl1271_warning("could not allocate HLID - too much stations");
2619 return -EBUSY;
2620 }
2621
2622 wl_sta = (struct wl1271_station *)sta->drv_priv;
2623
2624 __set_bit(id, wl->ap_hlid_map);
2625 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2626 *hlid = wl_sta->hlid;
2627 return 0;
2628}
2629
2630static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2631{
2632 int id = hlid - WL1271_AP_STA_HLID_START;
2633
2634 __clear_bit(id, wl->ap_hlid_map);
2635}
2636
2637static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2638 struct ieee80211_vif *vif,
2639 struct ieee80211_sta *sta)
2640{
2641 struct wl1271 *wl = hw->priv;
2642 int ret = 0;
2643 u8 hlid;
2644
2645 mutex_lock(&wl->mutex);
2646
2647 if (unlikely(wl->state == WL1271_STATE_OFF))
2648 goto out;
2649
2650 if (wl->bss_type != BSS_TYPE_AP_BSS)
2651 goto out;
2652
2653 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2654
2655 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2656 if (ret < 0)
2657 goto out;
2658
2659 ret = wl1271_ps_elp_wakeup(wl, false);
2660 if (ret < 0)
2661 goto out;
2662
2663 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2664 if (ret < 0)
2665 goto out_sleep;
2666
2667out_sleep:
2668 wl1271_ps_elp_sleep(wl);
2669
2670out:
2671 mutex_unlock(&wl->mutex);
2672 return ret;
2673}
2674
2675static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2676 struct ieee80211_vif *vif,
2677 struct ieee80211_sta *sta)
2678{
2679 struct wl1271 *wl = hw->priv;
2680 struct wl1271_station *wl_sta;
2681 int ret = 0, id;
2682
2683 mutex_lock(&wl->mutex);
2684
2685 if (unlikely(wl->state == WL1271_STATE_OFF))
2686 goto out;
2687
2688 if (wl->bss_type != BSS_TYPE_AP_BSS)
2689 goto out;
2690
2691 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2692
2693 wl_sta = (struct wl1271_station *)sta->drv_priv;
2694 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2695 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2696 goto out;
2697
2698 ret = wl1271_ps_elp_wakeup(wl, false);
2699 if (ret < 0)
2700 goto out;
2701
2702 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2703 if (ret < 0)
2704 goto out_sleep;
2705
2706 wl1271_free_hlid(wl, wl_sta->hlid);
2707
2708out_sleep:
2709 wl1271_ps_elp_sleep(wl);
2710
2711out:
2712 mutex_unlock(&wl->mutex);
2713 return ret;
2714}
2715
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716/* can't be const, mac80211 writes to this */
2717static struct ieee80211_rate wl1271_rates[] = {
2718 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002719 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2720 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002722 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2723 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2725 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002726 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2727 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2729 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002730 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2731 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2733 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002734 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2735 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002737 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2738 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002739 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002740 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2741 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002742 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002743 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2744 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002745 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002746 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2747 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002748 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002749 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2750 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002751 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002752 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2753 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002754 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002755 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2756 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002757};
2758
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002759/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002760static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002761 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002762 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002763 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2764 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2765 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002766 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002767 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2768 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2769 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002770 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002771 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2772 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2773 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002774};
2775
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002776/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002777static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002778 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002779 7, /* CONF_HW_RXTX_RATE_MCS7 */
2780 6, /* CONF_HW_RXTX_RATE_MCS6 */
2781 5, /* CONF_HW_RXTX_RATE_MCS5 */
2782 4, /* CONF_HW_RXTX_RATE_MCS4 */
2783 3, /* CONF_HW_RXTX_RATE_MCS3 */
2784 2, /* CONF_HW_RXTX_RATE_MCS2 */
2785 1, /* CONF_HW_RXTX_RATE_MCS1 */
2786 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002787
2788 11, /* CONF_HW_RXTX_RATE_54 */
2789 10, /* CONF_HW_RXTX_RATE_48 */
2790 9, /* CONF_HW_RXTX_RATE_36 */
2791 8, /* CONF_HW_RXTX_RATE_24 */
2792
2793 /* TI-specific rate */
2794 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2795
2796 7, /* CONF_HW_RXTX_RATE_18 */
2797 6, /* CONF_HW_RXTX_RATE_12 */
2798 3, /* CONF_HW_RXTX_RATE_11 */
2799 5, /* CONF_HW_RXTX_RATE_9 */
2800 4, /* CONF_HW_RXTX_RATE_6 */
2801 2, /* CONF_HW_RXTX_RATE_5_5 */
2802 1, /* CONF_HW_RXTX_RATE_2 */
2803 0 /* CONF_HW_RXTX_RATE_1 */
2804};
2805
Shahar Levie8b03a22010-10-13 16:09:39 +02002806/* 11n STA capabilities */
2807#define HW_RX_HIGHEST_RATE 72
2808
Shahar Levi00d20102010-11-08 11:20:10 +00002809#ifdef CONFIG_WL12XX_HT
2810#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002811 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2812 .ht_supported = true, \
2813 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2814 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2815 .mcs = { \
2816 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2817 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2818 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2819 }, \
2820}
Shahar Levi18357852010-10-13 16:09:41 +02002821#else
Shahar Levi00d20102010-11-08 11:20:10 +00002822#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002823 .ht_supported = false, \
2824}
2825#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827/* can't be const, mac80211 writes to this */
2828static struct ieee80211_supported_band wl1271_band_2ghz = {
2829 .channels = wl1271_channels,
2830 .n_channels = ARRAY_SIZE(wl1271_channels),
2831 .bitrates = wl1271_rates,
2832 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002833 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002834};
2835
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002836/* 5 GHz data rates for WL1273 */
2837static struct ieee80211_rate wl1271_rates_5ghz[] = {
2838 { .bitrate = 60,
2839 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2840 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2841 { .bitrate = 90,
2842 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2843 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2844 { .bitrate = 120,
2845 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2846 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2847 { .bitrate = 180,
2848 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2849 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2850 { .bitrate = 240,
2851 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2852 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2853 { .bitrate = 360,
2854 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2855 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2856 { .bitrate = 480,
2857 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2858 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2859 { .bitrate = 540,
2860 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2861 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2862};
2863
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002864/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002865static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002866 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002867 { .hw_value = 8, .center_freq = 5040},
2868 { .hw_value = 9, .center_freq = 5045},
2869 { .hw_value = 11, .center_freq = 5055},
2870 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002871 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002872 { .hw_value = 34, .center_freq = 5170},
2873 { .hw_value = 36, .center_freq = 5180},
2874 { .hw_value = 38, .center_freq = 5190},
2875 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002876 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002877 { .hw_value = 44, .center_freq = 5220},
2878 { .hw_value = 46, .center_freq = 5230},
2879 { .hw_value = 48, .center_freq = 5240},
2880 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002881 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002882 { .hw_value = 60, .center_freq = 5300},
2883 { .hw_value = 64, .center_freq = 5320},
2884 { .hw_value = 100, .center_freq = 5500},
2885 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002886 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002887 { .hw_value = 112, .center_freq = 5560},
2888 { .hw_value = 116, .center_freq = 5580},
2889 { .hw_value = 120, .center_freq = 5600},
2890 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002891 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002892 { .hw_value = 132, .center_freq = 5660},
2893 { .hw_value = 136, .center_freq = 5680},
2894 { .hw_value = 140, .center_freq = 5700},
2895 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002896 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002897 { .hw_value = 157, .center_freq = 5785},
2898 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002899 { .hw_value = 165, .center_freq = 5825},
2900};
2901
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002902/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002903static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002904 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002905 7, /* CONF_HW_RXTX_RATE_MCS7 */
2906 6, /* CONF_HW_RXTX_RATE_MCS6 */
2907 5, /* CONF_HW_RXTX_RATE_MCS5 */
2908 4, /* CONF_HW_RXTX_RATE_MCS4 */
2909 3, /* CONF_HW_RXTX_RATE_MCS3 */
2910 2, /* CONF_HW_RXTX_RATE_MCS2 */
2911 1, /* CONF_HW_RXTX_RATE_MCS1 */
2912 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002913
2914 7, /* CONF_HW_RXTX_RATE_54 */
2915 6, /* CONF_HW_RXTX_RATE_48 */
2916 5, /* CONF_HW_RXTX_RATE_36 */
2917 4, /* CONF_HW_RXTX_RATE_24 */
2918
2919 /* TI-specific rate */
2920 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2921
2922 3, /* CONF_HW_RXTX_RATE_18 */
2923 2, /* CONF_HW_RXTX_RATE_12 */
2924 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2925 1, /* CONF_HW_RXTX_RATE_9 */
2926 0, /* CONF_HW_RXTX_RATE_6 */
2927 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2928 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2929 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2930};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002931
2932static struct ieee80211_supported_band wl1271_band_5ghz = {
2933 .channels = wl1271_channels_5ghz,
2934 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2935 .bitrates = wl1271_rates_5ghz,
2936 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002937 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002938};
2939
Tobias Klausera0ea9492010-05-20 10:38:11 +02002940static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002941 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2942 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2943};
2944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945static const struct ieee80211_ops wl1271_ops = {
2946 .start = wl1271_op_start,
2947 .stop = wl1271_op_stop,
2948 .add_interface = wl1271_op_add_interface,
2949 .remove_interface = wl1271_op_remove_interface,
2950 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002951 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 .configure_filter = wl1271_op_configure_filter,
2953 .tx = wl1271_op_tx,
2954 .set_key = wl1271_op_set_key,
2955 .hw_scan = wl1271_op_hw_scan,
2956 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002957 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002959 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002960 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002961 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002962 .sta_add = wl1271_op_sta_add,
2963 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002964 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965};
2966
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002967
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002968u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002969{
2970 u8 idx;
2971
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002972 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002973
2974 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2975 wl1271_error("Illegal RX rate from HW: %d", rate);
2976 return 0;
2977 }
2978
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002979 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002980 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2981 wl1271_error("Unsupported RX rate from HW: %d", rate);
2982 return 0;
2983 }
2984
2985 return idx;
2986}
2987
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002988static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2989 struct device_attribute *attr,
2990 char *buf)
2991{
2992 struct wl1271 *wl = dev_get_drvdata(dev);
2993 ssize_t len;
2994
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002995 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002996
2997 mutex_lock(&wl->mutex);
2998 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2999 wl->sg_enabled);
3000 mutex_unlock(&wl->mutex);
3001
3002 return len;
3003
3004}
3005
3006static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3007 struct device_attribute *attr,
3008 const char *buf, size_t count)
3009{
3010 struct wl1271 *wl = dev_get_drvdata(dev);
3011 unsigned long res;
3012 int ret;
3013
3014 ret = strict_strtoul(buf, 10, &res);
3015
3016 if (ret < 0) {
3017 wl1271_warning("incorrect value written to bt_coex_mode");
3018 return count;
3019 }
3020
3021 mutex_lock(&wl->mutex);
3022
3023 res = !!res;
3024
3025 if (res == wl->sg_enabled)
3026 goto out;
3027
3028 wl->sg_enabled = res;
3029
3030 if (wl->state == WL1271_STATE_OFF)
3031 goto out;
3032
3033 ret = wl1271_ps_elp_wakeup(wl, false);
3034 if (ret < 0)
3035 goto out;
3036
3037 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3038 wl1271_ps_elp_sleep(wl);
3039
3040 out:
3041 mutex_unlock(&wl->mutex);
3042 return count;
3043}
3044
3045static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3046 wl1271_sysfs_show_bt_coex_state,
3047 wl1271_sysfs_store_bt_coex_state);
3048
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003049static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3050 struct device_attribute *attr,
3051 char *buf)
3052{
3053 struct wl1271 *wl = dev_get_drvdata(dev);
3054 ssize_t len;
3055
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003056 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003057
3058 mutex_lock(&wl->mutex);
3059 if (wl->hw_pg_ver >= 0)
3060 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3061 else
3062 len = snprintf(buf, len, "n/a\n");
3063 mutex_unlock(&wl->mutex);
3064
3065 return len;
3066}
3067
3068static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3069 wl1271_sysfs_show_hw_pg_ver, NULL);
3070
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003071int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072{
3073 int ret;
3074
3075 if (wl->mac80211_registered)
3076 return 0;
3077
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003078 ret = wl1271_fetch_nvs(wl);
3079 if (ret == 0) {
3080 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3081
3082 wl->mac_addr[0] = nvs_ptr[11];
3083 wl->mac_addr[1] = nvs_ptr[10];
3084 wl->mac_addr[2] = nvs_ptr[6];
3085 wl->mac_addr[3] = nvs_ptr[5];
3086 wl->mac_addr[4] = nvs_ptr[4];
3087 wl->mac_addr[5] = nvs_ptr[3];
3088 }
3089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3091
3092 ret = ieee80211_register_hw(wl->hw);
3093 if (ret < 0) {
3094 wl1271_error("unable to register mac80211 hw: %d", ret);
3095 return ret;
3096 }
3097
3098 wl->mac80211_registered = true;
3099
Eliad Pellerd60080a2010-11-24 12:53:16 +02003100 wl1271_debugfs_init(wl);
3101
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003102 register_netdevice_notifier(&wl1271_dev_notifier);
3103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003104 wl1271_notice("loaded");
3105
3106 return 0;
3107}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003108EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003110void wl1271_unregister_hw(struct wl1271 *wl)
3111{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003112 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003113 ieee80211_unregister_hw(wl->hw);
3114 wl->mac80211_registered = false;
3115
3116}
3117EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3118
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003119int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003120{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003121 static const u32 cipher_suites[] = {
3122 WLAN_CIPHER_SUITE_WEP40,
3123 WLAN_CIPHER_SUITE_WEP104,
3124 WLAN_CIPHER_SUITE_TKIP,
3125 WLAN_CIPHER_SUITE_CCMP,
3126 WL1271_CIPHER_SUITE_GEM,
3127 };
3128
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003129 /* The tx descriptor buffer and the TKIP space. */
3130 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3131 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003132
3133 /* unit us */
3134 /* FIXME: find a proper value */
3135 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003136 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137
3138 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003139 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003140 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003141 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003142 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003143 IEEE80211_HW_CONNECTION_MONITOR |
3144 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003146 wl->hw->wiphy->cipher_suites = cipher_suites;
3147 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3148
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003149 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003150 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003151 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003152 /*
3153 * Maximum length of elements in scanning probe request templates
3154 * should be the maximum length possible for a template, without
3155 * the IEEE80211 header of the template
3156 */
3157 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3158 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003159
3160 /*
3161 * We keep local copies of the band structs because we need to
3162 * modify them on a per-device basis.
3163 */
3164 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3165 sizeof(wl1271_band_2ghz));
3166 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3167 sizeof(wl1271_band_5ghz));
3168
3169 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3170 &wl->bands[IEEE80211_BAND_2GHZ];
3171 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3172 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003173
Kalle Valo12bd8942010-03-18 12:26:33 +02003174 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003175 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003176
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003177 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3178
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003179 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003180
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003181 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3182
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003183 return 0;
3184}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003185EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003186
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003187#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003188
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003189struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003190{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003191 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003192 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003193 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003194 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003195 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196
3197 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3198 if (!hw) {
3199 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003200 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003201 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003202 }
3203
Julia Lawall929ebd32010-05-15 23:16:39 +02003204 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003205 if (!plat_dev) {
3206 wl1271_error("could not allocate platform_device");
3207 ret = -ENOMEM;
3208 goto err_plat_alloc;
3209 }
3210
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211 wl = hw->priv;
3212 memset(wl, 0, sizeof(*wl));
3213
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003214 INIT_LIST_HEAD(&wl->list);
3215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003217 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003219 for (i = 0; i < NUM_TX_QUEUES; i++)
3220 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003221
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003222 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003223 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003224 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3225 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3226 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3227 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003229 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003230 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003232 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3233 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003234 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003236 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003237 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003238 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3239 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003240 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003241 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003242 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003243 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003244 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003245 wl->bss_type = MAX_BSS_TYPE;
3246 wl->set_bss_type = MAX_BSS_TYPE;
3247 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003248
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003249 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003250 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003251 wl->tx_frames[i] = NULL;
3252
3253 spin_lock_init(&wl->wl_lock);
3254
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255 wl->state = WL1271_STATE_OFF;
3256 mutex_init(&wl->mutex);
3257
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003258 /* Apply default driver configuration. */
3259 wl1271_conf_init(wl);
3260
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003261 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3262 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3263 if (!wl->aggr_buf) {
3264 ret = -ENOMEM;
3265 goto err_hw;
3266 }
3267
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003268 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003269 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003270 if (ret) {
3271 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003272 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003273 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003274 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003275
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003276 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003277 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003278 if (ret < 0) {
3279 wl1271_error("failed to create sysfs file bt_coex_state");
3280 goto err_platform;
3281 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003282
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003283 /* Create sysfs file to get HW PG version */
3284 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3285 if (ret < 0) {
3286 wl1271_error("failed to create sysfs file hw_pg_ver");
3287 goto err_bt_coex_state;
3288 }
3289
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003290 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003291
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003292err_bt_coex_state:
3293 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3294
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003295err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003296 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003297
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003298err_aggr:
3299 free_pages((unsigned long)wl->aggr_buf, order);
3300
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003301err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003302 wl1271_debugfs_exit(wl);
3303 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003304
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003305err_plat_alloc:
3306 ieee80211_free_hw(hw);
3307
3308err_hw_alloc:
3309
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003310 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003311}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003312EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003313
3314int wl1271_free_hw(struct wl1271 *wl)
3315{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003316 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003317 free_pages((unsigned long)wl->aggr_buf,
3318 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003319 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003320
3321 wl1271_debugfs_exit(wl);
3322
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003323 vfree(wl->fw);
3324 wl->fw = NULL;
3325 kfree(wl->nvs);
3326 wl->nvs = NULL;
3327
3328 kfree(wl->fw_status);
3329 kfree(wl->tx_res_if);
3330
3331 ieee80211_free_hw(wl->hw);
3332
3333 return 0;
3334}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003335EXPORT_SYMBOL_GPL(wl1271_free_hw);
3336
Eliad Peller17c17552010-12-12 12:15:35 +02003337u32 wl12xx_debug_level;
3338EXPORT_SYMBOL_GPL(wl12xx_debug_level);
3339module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE);
3340MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3341
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003342MODULE_LICENSE("GPL");
3343MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3344MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");