blob: 32d877f1c684f8e422990d99d0def971c6207253 [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
Luciano Coelho8f6ac532013-05-04 01:06:11 +03003 * This file is part of wlcore
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelho8f6ac532013-05-04 01:06:11 +03006 * Copyright (C) 2011-2013 Texas Instruments Inc.
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03007 *
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>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030027#include <linux/vmalloc.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020028#include <linux/wl12xx.h>
Felipe Balbia390e852011-10-06 10:07:44 +030029#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030030
Luciano Coelhoc31be252011-11-21 19:25:24 +020031#include "wlcore.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030032#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "io.h"
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "tx.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "ps.h"
37#include "init.h"
38#include "debugfs.h"
Shahar Levi00d20102010-11-08 11:20:10 +000039#include "testmode.h"
40#include "scan.h"
Arik Nemtsov53d67a52011-12-12 11:32:37 +020041#include "hw_ops.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030042
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020043#define WL1271_BOOT_RETRIES 3
44
Ido Yariv95dac04f2011-06-06 14:57:06 +030045static char *fwlog_param;
Yair Shapira72303412012-11-26 18:05:50 +020046static int bug_on_recovery = -1;
47static int no_recovery = -1;
Ido Yariv95dac04f2011-06-06 14:57:06 +030048
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030049static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +020050 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030051 bool reset_tx_queues);
Ido Yarivc24ec832012-06-26 21:08:58 +030052static void wlcore_op_stop_locked(struct wl1271 *wl);
Eliad Peller170d0e62011-10-05 11:56:06 +020053static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +020054
Luciano Coelho8f6ac532013-05-04 01:06:11 +030055static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pelleref4b29e2011-06-06 13:03:12 +030056{
57 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +020058
Eliad Peller9fd6f212012-03-04 10:55:48 +020059 if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
60 return -EINVAL;
61
62 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030063 return 0;
64
Eliad Peller8181aec2011-10-10 10:13:04 +020065 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030066 return 0;
67
Eliad Pellerd50529c2012-11-22 18:06:20 +020068 ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +030069 if (ret < 0)
70 return ret;
71
72 wl1271_info("Association completed.");
73 return 0;
74}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +030075
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +000076static void wl1271_reg_notify(struct wiphy *wiphy,
77 struct regulatory_request *request)
Luciano Coelho573c67c2010-11-26 13:44:59 +020078{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010079 struct ieee80211_supported_band *band;
80 struct ieee80211_channel *ch;
81 int i;
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +020082 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
83 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010084
85 band = wiphy->bands[IEEE80211_BAND_5GHZ];
86 for (i = 0; i < band->n_channels; i++) {
87 ch = &band->channels[i];
88 if (ch->flags & IEEE80211_CHAN_DISABLED)
89 continue;
90
91 if (ch->flags & IEEE80211_CHAN_RADAR)
92 ch->flags |= IEEE80211_CHAN_NO_IBSS |
93 IEEE80211_CHAN_PASSIVE_SCAN;
94
95 }
96
Arik Nemtsov75592be2013-03-12 17:19:45 +020097 wlcore_regdomain_config(wl);
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010098}
99
Eliad Peller9eb599e2011-10-10 10:12:59 +0200100static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
101 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300102{
103 int ret = 0;
104
105 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200106 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300107 if (ret < 0)
108 goto out;
109
110 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200111 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300112 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200113 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300114out:
115 return ret;
116}
117
118/*
119 * this function is being called when the rx_streaming interval
120 * has beed changed or rx_streaming should be disabled
121 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200122int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300123{
124 int ret = 0;
125 int period = wl->conf.rx_streaming.interval;
126
127 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200128 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300129 goto out;
130
131 /* reconfigure/disable according to new streaming_period */
132 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200133 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300134 (wl->conf.rx_streaming.always ||
135 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200136 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300137 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200138 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300139 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200140 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300141 }
142out:
143 return ret;
144}
145
146static void wl1271_rx_streaming_enable_work(struct work_struct *work)
147{
148 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200149 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
150 rx_streaming_enable_work);
151 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300152
153 mutex_lock(&wl->mutex);
154
Eliad Peller0744bdb2011-10-10 10:13:05 +0200155 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200156 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300157 (!wl->conf.rx_streaming.always &&
158 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
159 goto out;
160
161 if (!wl->conf.rx_streaming.interval)
162 goto out;
163
164 ret = wl1271_ps_elp_wakeup(wl);
165 if (ret < 0)
166 goto out;
167
Eliad Peller9eb599e2011-10-10 10:12:59 +0200168 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300169 if (ret < 0)
170 goto out_sleep;
171
172 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200173 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300174 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
175
176out_sleep:
177 wl1271_ps_elp_sleep(wl);
178out:
179 mutex_unlock(&wl->mutex);
180}
181
182static void wl1271_rx_streaming_disable_work(struct work_struct *work)
183{
184 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200185 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
186 rx_streaming_disable_work);
187 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300188
189 mutex_lock(&wl->mutex);
190
Eliad Peller0744bdb2011-10-10 10:13:05 +0200191 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300192 goto out;
193
194 ret = wl1271_ps_elp_wakeup(wl);
195 if (ret < 0)
196 goto out;
197
Eliad Peller9eb599e2011-10-10 10:12:59 +0200198 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300199 if (ret)
200 goto out_sleep;
201
202out_sleep:
203 wl1271_ps_elp_sleep(wl);
204out:
205 mutex_unlock(&wl->mutex);
206}
207
208static void wl1271_rx_streaming_timer(unsigned long data)
209{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200210 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
211 struct wl1271 *wl = wlvif->wl;
212 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300213}
214
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200215/* wl->mutex must be taken */
216void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
217{
218 /* if the watchdog is not armed, don't do anything */
219 if (wl->tx_allocated_blocks == 0)
220 return;
221
222 cancel_delayed_work(&wl->tx_watchdog_work);
223 ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work,
224 msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
225}
226
227static void wl12xx_tx_watchdog_work(struct work_struct *work)
228{
229 struct delayed_work *dwork;
230 struct wl1271 *wl;
231
232 dwork = container_of(work, struct delayed_work, work);
233 wl = container_of(dwork, struct wl1271, tx_watchdog_work);
234
235 mutex_lock(&wl->mutex);
236
Ido Yariv4cc53382012-07-24 19:18:49 +0300237 if (unlikely(wl->state != WLCORE_STATE_ON))
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200238 goto out;
239
240 /* Tx went out in the meantime - everything is ok */
241 if (unlikely(wl->tx_allocated_blocks == 0))
242 goto out;
243
244 /*
245 * if a ROC is in progress, we might not have any Tx for a long
246 * time (e.g. pending Tx on the non-ROC channels)
247 */
248 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
249 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC",
250 wl->conf.tx.tx_watchdog_timeout);
251 wl12xx_rearm_tx_watchdog_locked(wl);
252 goto out;
253 }
254
255 /*
256 * if a scan is in progress, we might not have any Tx for a long
257 * time
258 */
259 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
260 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan",
261 wl->conf.tx.tx_watchdog_timeout);
262 wl12xx_rearm_tx_watchdog_locked(wl);
263 goto out;
264 }
265
266 /*
267 * AP might cache a frame for a long time for a sleeping station,
268 * so rearm the timer if there's an AP interface with stations. If
269 * Tx is genuinely stuck we will most hopefully discover it when all
270 * stations are removed due to inactivity.
271 */
272 if (wl->active_sta_count) {
273 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has "
274 " %d stations",
275 wl->conf.tx.tx_watchdog_timeout,
276 wl->active_sta_count);
277 wl12xx_rearm_tx_watchdog_locked(wl);
278 goto out;
279 }
280
281 wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery",
282 wl->conf.tx.tx_watchdog_timeout);
283 wl12xx_queue_recovery_work(wl);
284
285out:
286 mutex_unlock(&wl->mutex);
287}
288
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200289static void wlcore_adjust_conf(struct wl1271 *wl)
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300290{
Ido Yariv95dac04f2011-06-06 14:57:06 +0300291 /* Adjust settings according to optional module parameters */
Yair Shapira72303412012-11-26 18:05:50 +0200292
Ido Yariv95dac04f2011-06-06 14:57:06 +0300293 if (fwlog_param) {
294 if (!strcmp(fwlog_param, "continuous")) {
295 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
296 } else if (!strcmp(fwlog_param, "ondemand")) {
297 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
298 } else if (!strcmp(fwlog_param, "dbgpins")) {
299 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
300 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
301 } else if (!strcmp(fwlog_param, "disable")) {
302 wl->conf.fwlog.mem_blocks = 0;
303 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
304 } else {
305 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
306 }
307 }
Yair Shapira72303412012-11-26 18:05:50 +0200308
309 if (bug_on_recovery != -1)
310 wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery;
311
312 if (no_recovery != -1)
313 wl->conf.recovery.no_recovery = (u8) no_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300314}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300315
Eliad Peller6e8cd332011-10-10 10:13:13 +0200316static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
317 struct wl12xx_vif *wlvif,
318 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200319{
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200320 bool fw_ps;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200321
Arik Nemtsovb622d992011-02-23 00:22:31 +0200322 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
323
324 /*
325 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300326 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200327 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300328 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200329 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200330
Arik Nemtsovda032092011-08-25 12:43:15 +0300331 /*
332 * Start high-level PS if the STA is asleep with enough blocks in FW.
Arik Nemtsov9a100962012-11-28 11:42:42 +0200333 * Make an exception if this is the only connected link. In this
334 * case FW-memory congestion is less of a problem.
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200335 * Note that a single connected STA means 3 active links, since we must
336 * account for the global and broadcast AP links. The "fw_ps" check
337 * assures us the third link is a STA connected to the AP. Otherwise
338 * the FW would not set the PSM bit.
Arik Nemtsovda032092011-08-25 12:43:15 +0300339 */
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200340 else if (wl->active_link_count > 3 && fw_ps &&
341 tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200342 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200343}
344
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300345static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200346 struct wl12xx_vif *wlvif,
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300347 struct wl_fw_status_2 *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200348{
349 u32 cur_fw_ps_map;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200350 u8 hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200351
352 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
353 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
354 wl1271_debug(DEBUG_PSM,
355 "link ps prev 0x%x cur 0x%x changed 0x%x",
356 wl->ap_fw_ps_map, cur_fw_ps_map,
357 wl->ap_fw_ps_map ^ cur_fw_ps_map);
358
359 wl->ap_fw_ps_map = cur_fw_ps_map;
360 }
361
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200362 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200363 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200364 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200365}
366
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300367static int wlcore_fw_status(struct wl1271 *wl,
368 struct wl_fw_status_1 *status_1,
369 struct wl_fw_status_2 *status_2)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300370{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200371 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200372 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200373 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300374 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300375 int i;
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200376 size_t status_len;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300377 int ret;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200378 struct wl1271_link *lnk;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300379
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300380 status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
381 sizeof(*status_2) + wl->fw_status_priv_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300383 ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
384 status_len, false);
385 if (ret < 0)
386 return ret;
Shahar Levi13b107d2011-03-06 16:32:12 +0200387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300388 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
389 "drv_rx_counter = %d, tx_results_counter = %d)",
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300390 status_1->intr,
391 status_1->fw_rx_counter,
392 status_1->drv_rx_counter,
393 status_1->tx_results_counter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300394
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300395 for (i = 0; i < NUM_TX_QUEUES; i++) {
396 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300397 wl->tx_allocated_pkts[i] -=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300398 (status_2->counters.tx_released_pkts[i] -
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300399 wl->tx_pkts_freed[i]) & 0xff;
400
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300401 wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300402 }
403
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200404
405 for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200406 u8 diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200407 lnk = &wl->links[i];
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200408
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200409 /* prevent wrap-around in freed-packets counter */
410 diff = (status_2->counters.tx_lnk_free_pkts[i] -
411 lnk->prev_freed_pkts) & 0xff;
412
413 if (diff == 0)
414 continue;
415
416 lnk->allocated_pkts -= diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200417 lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200418
419 /* accumulate the prev_freed_pkts counter */
420 lnk->total_freed_pkts += diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200421 }
422
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300423 /* prevent wrap-around in total blocks counter */
424 if (likely(wl->tx_blocks_freed <=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300425 le32_to_cpu(status_2->total_released_blks)))
426 freed_blocks = le32_to_cpu(status_2->total_released_blks) -
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300427 wl->tx_blocks_freed;
428 else
429 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300430 le32_to_cpu(status_2->total_released_blks);
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300431
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300432 wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200433
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300434 wl->tx_allocated_blocks -= freed_blocks;
435
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200436 /*
437 * If the FW freed some blocks:
438 * If we still have allocated blocks - re-arm the timer, Tx is
439 * not stuck. Otherwise, cancel the timer (no Tx currently).
440 */
441 if (freed_blocks) {
442 if (wl->tx_allocated_blocks)
443 wl12xx_rearm_tx_watchdog_locked(wl);
444 else
445 cancel_delayed_work(&wl->tx_watchdog_work);
446 }
447
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300448 avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200449
Eliad Peller4d56ad92011-08-14 13:17:05 +0300450 /*
451 * The FW might change the total number of TX memblocks before
452 * we get a notification about blocks being released. Thus, the
453 * available blocks calculation might yield a temporary result
454 * which is lower than the actual available blocks. Keeping in
455 * mind that only blocks that were allocated can be moved from
456 * TX to RX, tx_blocks_available should never decrease here.
457 */
458 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
459 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Ido Yariva5225502010-10-12 14:49:10 +0200461 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200462 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200463 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Eliad Peller4d56ad92011-08-14 13:17:05 +0300465 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200466 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300467 wl12xx_irq_update_links_status(wl, wlvif, status_2);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200468 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200471 getnstimeofday(&ts);
472 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300473 (s64)le32_to_cpu(status_2->fw_localtime);
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300474
Arik Nemtsov0e810472012-11-27 08:45:00 +0200475 wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
476
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300477 return 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300478}
479
Ido Yariva6208652011-03-01 15:14:41 +0200480static void wl1271_flush_deferred_work(struct wl1271 *wl)
481{
482 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200483
Ido Yariva6208652011-03-01 15:14:41 +0200484 /* Pass all received frames to the network stack */
485 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
486 ieee80211_rx_ni(wl->hw, skb);
487
488 /* Return sent skbs to the network stack */
489 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300490 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200491}
492
493static void wl1271_netstack_work(struct work_struct *work)
494{
495 struct wl1271 *wl =
496 container_of(work, struct wl1271, netstack_work);
497
498 do {
499 wl1271_flush_deferred_work(wl);
500 } while (skb_queue_len(&wl->deferred_rx_queue));
501}
502
503#define WL1271_IRQ_MAX_LOOPS 256
504
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300505static int wlcore_irq_locked(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300506{
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300507 int ret = 0;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300508 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200510 bool done = false;
511 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200512 unsigned long flags;
513
Ido Yariv341b7cd2011-03-31 10:07:01 +0200514 /*
515 * In case edge triggered interrupt must be used, we cannot iterate
516 * more than once without introducing race conditions with the hardirq.
517 */
518 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
519 loopcount = 1;
520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521 wl1271_debug(DEBUG_IRQ, "IRQ work");
522
Ido Yariv4cc53382012-07-24 19:18:49 +0300523 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524 goto out;
525
Ido Yariva6208652011-03-01 15:14:41 +0200526 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527 if (ret < 0)
528 goto out;
529
Ido Yariva6208652011-03-01 15:14:41 +0200530 while (!done && loopcount--) {
531 /*
532 * In order to avoid a race with the hardirq, clear the flag
533 * before acknowledging the chip. Since the mutex is held,
534 * wl1271_ps_elp_wakeup cannot be called concurrently.
535 */
536 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
537 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200538
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300539 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300540 if (ret < 0)
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300541 goto out;
Arik Nemtsov53d67a52011-12-12 11:32:37 +0200542
543 wlcore_hw_tx_immediate_compl(wl);
544
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300545 intr = le32_to_cpu(wl->fw_status_1->intr);
Ido Reisf5755fe2012-04-23 17:35:25 +0300546 intr &= WLCORE_ALL_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200547 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200548 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200549 continue;
550 }
551
Eliad Pellerccc83b02010-10-27 14:09:57 +0200552 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
Ido Reisf5755fe2012-04-23 17:35:25 +0300553 wl1271_error("HW watchdog interrupt received! starting recovery.");
554 wl->watchdog_recovery = true;
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300555 ret = -EIO;
Ido Reisf5755fe2012-04-23 17:35:25 +0300556
557 /* restarting the chip. ignore any other interrupt. */
558 goto out;
559 }
560
561 if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
562 wl1271_error("SW watchdog interrupt received! "
Eliad Pellerccc83b02010-10-27 14:09:57 +0200563 "starting recovery.");
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300564 wl->watchdog_recovery = true;
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300565 ret = -EIO;
Eliad Pellerccc83b02010-10-27 14:09:57 +0200566
567 /* restarting the chip. ignore any other interrupt. */
568 goto out;
569 }
570
Ido Yariva6208652011-03-01 15:14:41 +0200571 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200572 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
573
Ido Yariv045b9b52012-06-18 12:31:16 +0300574 ret = wlcore_rx(wl, wl->fw_status_1);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300575 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300576 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200577
Ido Yariva5225502010-10-12 14:49:10 +0200578 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200579 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200580 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300581 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200582 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200583 /*
584 * In order to avoid starvation of the TX path,
585 * call the work function directly.
586 */
Ido Yariveb96f842012-06-18 13:21:55 +0300587 ret = wlcore_tx_work_locked(wl);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300588 if (ret < 0)
Ido Yariveb96f842012-06-18 13:21:55 +0300589 goto out;
Ido Yarivb07d4032011-03-01 15:14:43 +0200590 } else {
591 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200592 }
593
Ido Yariv8aad2462011-03-01 15:14:38 +0200594 /* check for tx results */
Ido Yariv045b9b52012-06-18 12:31:16 +0300595 ret = wlcore_hw_tx_delayed_compl(wl);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300596 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300597 goto out;
Ido Yariva6208652011-03-01 15:14:41 +0200598
599 /* Make sure the deferred queues don't get too long */
600 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
601 skb_queue_len(&wl->deferred_rx_queue);
602 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
603 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200604 }
605
606 if (intr & WL1271_ACX_INTR_EVENT_A) {
607 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Ido Yariv045b9b52012-06-18 12:31:16 +0300608 ret = wl1271_event_handle(wl, 0);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300609 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300610 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200611 }
612
613 if (intr & WL1271_ACX_INTR_EVENT_B) {
614 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Ido Yariv045b9b52012-06-18 12:31:16 +0300615 ret = wl1271_event_handle(wl, 1);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300616 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300617 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200618 }
619
620 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
621 wl1271_debug(DEBUG_IRQ,
622 "WL1271_ACX_INTR_INIT_COMPLETE");
623
624 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
625 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626 }
627
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628 wl1271_ps_elp_sleep(wl);
629
630out:
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300631 return ret;
632}
633
634static irqreturn_t wlcore_irq(int irq, void *cookie)
635{
636 int ret;
637 unsigned long flags;
638 struct wl1271 *wl = cookie;
639
Luciano Coelho97236a02013-03-08 09:41:53 +0200640 /* complete the ELP completion */
641 spin_lock_irqsave(&wl->wl_lock, flags);
642 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
643 if (wl->elp_compl) {
644 complete(wl->elp_compl);
645 wl->elp_compl = NULL;
646 }
647
648 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
649 /* don't enqueue a work right now. mark it as pending */
650 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
651 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
652 disable_irq_nosync(wl->irq);
653 pm_wakeup_event(wl->dev, 0);
654 spin_unlock_irqrestore(&wl->wl_lock, flags);
655 return IRQ_HANDLED;
656 }
657 spin_unlock_irqrestore(&wl->wl_lock, flags);
658
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300659 /* TX might be handled here, avoid redundant work */
660 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
661 cancel_work_sync(&wl->tx_work);
662
663 mutex_lock(&wl->mutex);
664
665 ret = wlcore_irq_locked(wl);
666 if (ret)
667 wl12xx_queue_recovery_work(wl);
668
Ido Yarivb07d4032011-03-01 15:14:43 +0200669 spin_lock_irqsave(&wl->wl_lock, flags);
670 /* In case TX was not handled here, queue TX work */
671 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
672 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300673 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200674 ieee80211_queue_work(wl->hw, &wl->tx_work);
675 spin_unlock_irqrestore(&wl->wl_lock, flags);
676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200678
679 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680}
681
Eliad Peller4549d092012-02-06 13:07:52 +0200682struct vif_counter_data {
683 u8 counter;
684
685 struct ieee80211_vif *cur_vif;
686 bool cur_vif_running;
687};
688
689static void wl12xx_vif_count_iter(void *data, u8 *mac,
690 struct ieee80211_vif *vif)
691{
692 struct vif_counter_data *counter = data;
693
694 counter->counter++;
695 if (counter->cur_vif == vif)
696 counter->cur_vif_running = true;
697}
698
699/* caller must not hold wl->mutex, as it might deadlock */
700static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
701 struct ieee80211_vif *cur_vif,
702 struct vif_counter_data *data)
703{
704 memset(data, 0, sizeof(*data));
705 data->cur_vif = cur_vif;
706
Johannes Berg8b2c9822012-11-06 20:23:30 +0100707 ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
Eliad Peller4549d092012-02-06 13:07:52 +0200708 wl12xx_vif_count_iter, data);
709}
710
Eliad Peller3fcdab72012-02-06 12:47:54 +0200711static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712{
713 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200714 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200715 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 int ret;
717
Eliad Peller3fcdab72012-02-06 12:47:54 +0200718 if (plt) {
719 fw_type = WL12XX_FW_TYPE_PLT;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200720 fw_name = wl->plt_fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200721 } else {
Eliad Peller4549d092012-02-06 13:07:52 +0200722 /*
723 * we can't call wl12xx_get_vif_count() here because
724 * wl->mutex is taken, so use the cached last_vif_count value
725 */
Eliad Peller9b1a0a72012-07-25 14:22:21 +0300726 if (wl->last_vif_count > 1 && wl->mr_fw_name) {
Eliad Peller4549d092012-02-06 13:07:52 +0200727 fw_type = WL12XX_FW_TYPE_MULTI;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200728 fw_name = wl->mr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200729 } else {
730 fw_type = WL12XX_FW_TYPE_NORMAL;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200731 fw_name = wl->sr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200732 }
Eliad Peller3fcdab72012-02-06 12:47:54 +0200733 }
734
735 if (wl->fw_type == fw_type)
736 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200737
738 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
739
Felipe Balbia390e852011-10-06 10:07:44 +0300740 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
742 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100743 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 return ret;
745 }
746
747 if (fw->size % 4) {
748 wl1271_error("firmware size is not multiple of 32 bits: %zu",
749 fw->size);
750 ret = -EILSEQ;
751 goto out;
752 }
753
Arik Nemtsov166d5042010-10-16 21:44:57 +0200754 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +0200755 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300756 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300757 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300758
759 if (!wl->fw) {
760 wl1271_error("could not allocate memory for the firmware");
761 ret = -ENOMEM;
762 goto out;
763 }
764
765 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766 ret = 0;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200767 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300768out:
769 release_firmware(fw);
770
771 return ret;
772}
773
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300774void wl12xx_queue_recovery_work(struct wl1271 *wl)
775{
Eyal Shapira680c6052012-06-26 10:41:17 +0300776 WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
777
Ido Yarivb666bb72012-05-21 01:10:11 +0300778 /* Avoid a recursive recovery */
Ido Yariv792a58a2012-08-15 15:09:30 +0300779 if (wl->state == WLCORE_STATE_ON) {
Ido Yariv4cc53382012-07-24 19:18:49 +0300780 wl->state = WLCORE_STATE_RESTARTING;
Ido Yariv792a58a2012-08-15 15:09:30 +0300781 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
Ido Yarivb666bb72012-05-21 01:10:11 +0300782 wlcore_disable_interrupts_nosync(wl);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300783 ieee80211_queue_work(wl->hw, &wl->recovery_work);
Ido Yarivb666bb72012-05-21 01:10:11 +0300784 }
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300785}
786
Ido Yariv95dac04f2011-06-06 14:57:06 +0300787size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
788{
789 size_t len = 0;
790
791 /* The FW log is a length-value list, find where the log end */
792 while (len < maxlen) {
793 if (memblock[len] == 0)
794 break;
795 if (len + memblock[len] + 1 > maxlen)
796 break;
797 len += memblock[len] + 1;
798 }
799
800 /* Make sure we have enough room */
801 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
802
803 /* Fill the FW log file, consumed by the sysfs fwlog entry */
804 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
805 wl->fwlog_size += len;
806
807 return len;
808}
809
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300810#define WLCORE_FW_LOG_END 0x2000000
811
Ido Yariv95dac04f2011-06-06 14:57:06 +0300812static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
813{
814 u32 addr;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300815 u32 offset;
816 u32 end_of_log;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300817 u8 *block;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300818 int ret;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300819
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200820 if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
Ido Yariv95dac04f2011-06-06 14:57:06 +0300821 (wl->conf.fwlog.mem_blocks == 0))
822 return;
823
824 wl1271_info("Reading FW panic log");
825
826 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
827 if (!block)
828 return;
829
830 /*
831 * Make sure the chip is awake and the logger isn't active.
Eliad Peller847cbeb2012-11-26 18:05:42 +0200832 * Do not send a stop fwlog command if the fw is hanged or if
833 * dbgpins are used (due to some fw bug).
Ido Yariv95dac04f2011-06-06 14:57:06 +0300834 */
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300835 if (wl1271_ps_elp_wakeup(wl))
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300836 goto out;
Eliad Peller847cbeb2012-11-26 18:05:42 +0200837 if (!wl->watchdog_recovery &&
838 wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300839 wl12xx_cmd_stop_fwlog(wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +0300840
841 /* Read the first memory block address */
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300842 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
843 if (ret < 0)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300844 goto out;
845
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300846 addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
847 if (!addr)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300848 goto out;
849
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300850 if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
851 offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
852 end_of_log = WLCORE_FW_LOG_END;
853 } else {
854 offset = sizeof(addr);
855 end_of_log = addr;
856 }
857
Ido Yariv95dac04f2011-06-06 14:57:06 +0300858 /* Traverse the memory blocks linked list */
Ido Yariv95dac04f2011-06-06 14:57:06 +0300859 do {
860 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
Ido Yariv2b800402012-06-18 18:15:50 +0300861 ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
862 false);
863 if (ret < 0)
864 goto out;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300865
866 /*
867 * Memory blocks are linked to one another. The first 4 bytes
868 * of each memory block hold the hardware address of the next
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300869 * one. The last memory block points to the first one in
870 * on demand mode and is equal to 0x2000000 in continuous mode.
Ido Yariv95dac04f2011-06-06 14:57:06 +0300871 */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300872 addr = le32_to_cpup((__le32 *)block);
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300873 if (!wl12xx_copy_fwlog(wl, block + offset,
874 WL12XX_HW_BLOCK_SIZE - offset))
Ido Yariv95dac04f2011-06-06 14:57:06 +0300875 break;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300876 } while (addr && (addr != end_of_log));
Ido Yariv95dac04f2011-06-06 14:57:06 +0300877
878 wake_up_interruptible(&wl->fwlog_waitq);
879
880out:
881 kfree(block);
882}
883
Ido Yariv61343232012-06-18 15:50:21 +0300884static void wlcore_print_recovery(struct wl1271 *wl)
885{
886 u32 pc = 0;
887 u32 hint_sts = 0;
888 int ret;
889
890 wl1271_info("Hardware recovery in progress. FW ver: %s",
891 wl->chip.fw_ver_str);
892
893 /* change partitions momentarily so we can read the FW pc */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300894 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
895 if (ret < 0)
896 return;
Ido Yariv61343232012-06-18 15:50:21 +0300897
898 ret = wlcore_read_reg(wl, REG_PC_ON_RECOVERY, &pc);
899 if (ret < 0)
900 return;
901
902 ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &hint_sts);
903 if (ret < 0)
904 return;
905
Luciano Coelhoc108c902012-11-26 18:05:49 +0200906 wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d",
907 pc, hint_sts, ++wl->recovery_count);
Ido Yariv61343232012-06-18 15:50:21 +0300908
909 wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
910}
911
912
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200913static void wl1271_recovery_work(struct work_struct *work)
914{
915 struct wl1271 *wl =
916 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +0200917 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +0200918 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200919
920 mutex_lock(&wl->mutex);
921
Ido Yariv4cc53382012-07-24 19:18:49 +0300922 if (wl->state == WLCORE_STATE_OFF || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +0200923 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200924
Arik Nemtsovaafec112012-06-25 22:26:19 +0300925 if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) {
926 wl12xx_read_fwlog_panic(wl);
927 wlcore_print_recovery(wl);
928 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200929
Yair Shapira72303412012-11-26 18:05:50 +0200930 BUG_ON(wl->conf.recovery.bug_on_recovery &&
Eliad Pellere9ba7152012-03-04 10:55:54 +0200931 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
Eliad Peller2a5bff02011-08-25 18:10:59 +0300932
Yair Shapira72303412012-11-26 18:05:50 +0200933 if (wl->conf.recovery.no_recovery) {
Arik Nemtsov34785be2011-12-08 13:06:45 +0200934 wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
Arik Nemtsov34785be2011-12-08 13:06:45 +0200935 goto out_unlock;
936 }
937
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300938 /* Prevent spurious TX during FW restart */
Arik Nemtsov66396112012-05-18 07:46:38 +0300939 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300940
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200941 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200942 while (!list_empty(&wl->wlvif_list)) {
943 wlvif = list_first_entry(&wl->wlvif_list,
944 struct wl12xx_vif, list);
945 vif = wl12xx_wlvif_to_vif(wlvif);
946 __wl1271_op_remove_interface(wl, vif, false);
947 }
Ido Yarivc24ec832012-06-26 21:08:58 +0300948
949 wlcore_op_stop_locked(wl);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300950
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200951 ieee80211_restart_hw(wl->hw);
952
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300953 /*
954 * Its safe to enable TX now - the queues are stopped after a request
955 * to restart the HW.
956 */
Arik Nemtsov66396112012-05-18 07:46:38 +0300957 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Ido Yarivc24ec832012-06-26 21:08:58 +0300958
Eliad Pellerf0277432011-10-10 10:13:14 +0200959out_unlock:
Arik Nemtsovb034fd62012-06-25 22:26:20 +0300960 wl->watchdog_recovery = false;
961 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200962 mutex_unlock(&wl->mutex);
963}
964
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300965static int wlcore_fw_wakeup(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966{
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300967 return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968}
969
970static int wl1271_setup(struct wl1271 *wl)
971{
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300972 wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
Luciano Coelho4f64a1e2012-05-10 12:14:00 +0300973 sizeof(*wl->fw_status_2) +
974 wl->fw_status_priv_len, GFP_KERNEL);
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300975 if (!wl->fw_status_1)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 return -ENOMEM;
977
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300978 wl->fw_status_2 = (struct wl_fw_status_2 *)
979 (((u8 *) wl->fw_status_1) +
980 WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
983 if (!wl->tx_res_if) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300984 kfree(wl->fw_status_1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 return -ENOMEM;
986 }
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 return 0;
989}
990
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200991static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200993 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200995 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200996 ret = wl1271_power_on(wl);
997 if (ret < 0)
998 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001000 wl1271_io_reset(wl);
1001 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001003 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
1004 if (ret < 0)
1005 goto fail;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006
1007 /* ELP module wake up */
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001008 ret = wlcore_fw_wakeup(wl);
1009 if (ret < 0)
1010 goto fail;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001012out:
1013 return ret;
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001014
1015fail:
1016 wl1271_power_off(wl);
1017 return ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001018}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019
Eliad Peller3fcdab72012-02-06 12:47:54 +02001020static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001021{
1022 int ret = 0;
1023
1024 ret = wl12xx_set_power_on(wl);
1025 if (ret < 0)
1026 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001028 /*
1029 * For wl127x based devices we could use the default block
1030 * size (512 bytes), but due to a bug in the sdio driver, we
1031 * need to set it explicitly after the chip is powered on. To
1032 * simplify the code and since the performance impact is
1033 * negligible, we use the same block size for all different
1034 * chip types.
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +03001035 *
1036 * Check if the bus supports blocksize alignment and, if it
1037 * doesn't, make sure we don't have the quirk.
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001038 */
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +03001039 if (!wl1271_set_block_size(wl))
1040 wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001042 /* TODO: make sure the lower driver has set things up correctly */
1043
1044 ret = wl1271_setup(wl);
1045 if (ret < 0)
1046 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
Eliad Peller3fcdab72012-02-06 12:47:54 +02001048 ret = wl12xx_fetch_firmware(wl, plt);
1049 if (ret < 0)
1050 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052out:
1053 return ret;
1054}
1055
Yair Shapira7019c802012-07-11 18:48:04 +03001056int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001058 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001059 struct wiphy *wiphy = wl->hw->wiphy;
Yair Shapira7019c802012-07-11 18:48:04 +03001060
1061 static const char* const PLT_MODE[] = {
1062 "PLT_OFF",
1063 "PLT_ON",
1064 "PLT_FEM_DETECT"
1065 };
1066
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067 int ret;
1068
1069 mutex_lock(&wl->mutex);
1070
1071 wl1271_notice("power up");
1072
Ido Yariv4cc53382012-07-24 19:18:49 +03001073 if (wl->state != WLCORE_STATE_OFF) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074 wl1271_error("cannot go into PLT state because not "
1075 "in off state: %d", wl->state);
1076 ret = -EBUSY;
1077 goto out;
1078 }
1079
Yair Shapira7019c802012-07-11 18:48:04 +03001080 /* Indicate to lower levels that we are now in PLT mode */
1081 wl->plt = true;
1082 wl->plt_mode = plt_mode;
1083
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001084 while (retries) {
1085 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001086 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001087 if (ret < 0)
1088 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089
Luciano Coelhoc331b342012-05-10 12:13:49 +03001090 ret = wl->ops->plt_init(wl);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001091 if (ret < 0)
1092 goto power_off;
1093
Ido Yariv4cc53382012-07-24 19:18:49 +03001094 wl->state = WLCORE_STATE_ON;
Yair Shapira7019c802012-07-11 18:48:04 +03001095 wl1271_notice("firmware booted in PLT mode %s (%s)",
1096 PLT_MODE[plt_mode],
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001097 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001098
Gery Kahn6f07b722011-07-18 14:21:49 +03001099 /* update hw/fw version info in wiphy struct */
1100 wiphy->hw_version = wl->chip.id;
1101 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1102 sizeof(wiphy->fw_version));
1103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 goto out;
1105
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001106power_off:
1107 wl1271_power_off(wl);
1108 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109
Yair Shapira7019c802012-07-11 18:48:04 +03001110 wl->plt = false;
1111 wl->plt_mode = PLT_OFF;
1112
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001113 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1114 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001115out:
1116 mutex_unlock(&wl->mutex);
1117
1118 return ret;
1119}
1120
Ido Yarivf3df1332012-01-11 09:42:39 +02001121int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122{
1123 int ret = 0;
1124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125 wl1271_notice("power down");
1126
Ido Yariv46b0cc92012-01-11 09:42:41 +02001127 /*
1128 * Interrupts must be disabled before setting the state to OFF.
1129 * Otherwise, the interrupt handler might be called and exit without
1130 * reading the interrupt status.
1131 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001132 wlcore_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001133 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001134 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001135 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001136
1137 /*
1138 * This will not necessarily enable interrupts as interrupts
1139 * may have been disabled when op_stop was called. It will,
1140 * however, balance the above call to disable_interrupts().
1141 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001142 wlcore_enable_interrupts(wl);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001143
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001144 wl1271_error("cannot power down because not in PLT "
1145 "state: %d", wl->state);
1146 ret = -EBUSY;
1147 goto out;
1148 }
1149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001151
Ido Yariva6208652011-03-01 15:14:41 +02001152 wl1271_flush_deferred_work(wl);
1153 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001154 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001155 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001156 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Ido Yariva4549692012-01-11 09:42:40 +02001157
1158 mutex_lock(&wl->mutex);
1159 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001160 wl->flags = 0;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001161 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Ido Yariv4cc53382012-07-24 19:18:49 +03001162 wl->state = WLCORE_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001163 wl->plt = false;
Yair Shapira7019c802012-07-11 18:48:04 +03001164 wl->plt_mode = PLT_OFF;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001165 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001166 mutex_unlock(&wl->mutex);
1167
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001168out:
1169 return ret;
1170}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001171
Thomas Huehn36323f82012-07-23 21:33:42 +02001172static void wl1271_op_tx(struct ieee80211_hw *hw,
1173 struct ieee80211_tx_control *control,
1174 struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175{
1176 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001177 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1178 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001179 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001180 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001181 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001182 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001184 if (!vif) {
1185 wl1271_debug(DEBUG_TX, "DROP skb with no vif");
1186 ieee80211_free_txskb(hw, skb);
1187 return;
1188 }
Eliad Peller0f168012011-10-11 13:52:25 +02001189
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001190 wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001191 mapping = skb_get_queue_mapping(skb);
1192 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001193
Thomas Huehn36323f82012-07-23 21:33:42 +02001194 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb, control->sta);
Ido Yarivb07d4032011-03-01 15:14:43 +02001195
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001196 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001197
Arik Nemtsov66396112012-05-18 07:46:38 +03001198 /*
1199 * drop the packet if the link is invalid or the queue is stopped
1200 * for any reason but watermark. Watermark is a "soft"-stop so we
1201 * allow these packets through.
1202 */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001203 if (hlid == WL12XX_INVALID_LINK_ID ||
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001204 (!test_bit(hlid, wlvif->links_map)) ||
Arik Nemtsovd6037d22012-11-28 11:42:44 +02001205 (wlcore_is_queue_stopped_locked(wl, wlvif, q) &&
1206 !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
Arik Nemtsov66396112012-05-18 07:46:38 +03001207 WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001208 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001209 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001210 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001211 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212
Eliad Peller8ccd16e2012-03-04 10:55:55 +02001213 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d",
1214 hlid, q, skb->len);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001215 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1216
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001217 wl->tx_queue_count[q]++;
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001218 wlvif->tx_queue_count[q]++;
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001219
1220 /*
1221 * The workqueue is slow to process the tx_queue and we need stop
1222 * the queue here, otherwise the queue will get too long.
1223 */
Arik Nemtsov1c33db72012-11-30 00:48:03 +02001224 if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
Arik Nemtsovd6037d22012-11-28 11:42:44 +02001225 !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
Arik Nemtsov8cdc44a2012-06-25 22:26:17 +03001226 WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001227 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
Arik Nemtsov1c33db72012-11-30 00:48:03 +02001228 wlcore_stop_queue_locked(wl, wlvif, q,
Arik Nemtsov66396112012-05-18 07:46:38 +03001229 WLCORE_QUEUE_STOP_REASON_WATERMARK);
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 /*
1233 * The chip specific setup must run before the first TX packet -
1234 * before that, the tx_work will not be initialized!
1235 */
1236
Ido Yarivb07d4032011-03-01 15:14:43 +02001237 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1238 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001239 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001240
Arik Nemtsov04216da2011-08-14 13:17:38 +03001241out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001242 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243}
1244
Shahar Leviae47c452011-03-06 16:32:14 +02001245int wl1271_tx_dummy_packet(struct wl1271 *wl)
1246{
Ido Yariv990f5de2011-03-31 10:06:59 +02001247 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001248 int q;
1249
1250 /* no need to queue a new dummy packet if one is already pending */
1251 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1252 return 0;
1253
1254 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001255
Ido Yariv990f5de2011-03-31 10:06:59 +02001256 spin_lock_irqsave(&wl->wl_lock, flags);
1257 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001258 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001259 spin_unlock_irqrestore(&wl->wl_lock, flags);
1260
1261 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1262 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Ido Yariveb96f842012-06-18 13:21:55 +03001263 return wlcore_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001264
1265 /*
1266 * If the FW TX is busy, TX work will be scheduled by the threaded
1267 * interrupt handler function
1268 */
1269 return 0;
1270}
1271
1272/*
1273 * The size of the dummy packet should be at least 1400 bytes. However, in
1274 * order to minimize the number of bus transactions, aligning it to 512 bytes
1275 * boundaries could be beneficial, performance wise
1276 */
1277#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1278
Luciano Coelhocf27d862011-04-01 21:08:23 +03001279static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001280{
1281 struct sk_buff *skb;
1282 struct ieee80211_hdr_3addr *hdr;
1283 unsigned int dummy_packet_size;
1284
1285 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1286 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1287
1288 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001289 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001290 wl1271_warning("Failed to allocate a dummy packet skb");
1291 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001292 }
1293
1294 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1295
1296 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1297 memset(hdr, 0, sizeof(*hdr));
1298 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001299 IEEE80211_STYPE_NULLFUNC |
1300 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001301
Ido Yariv990f5de2011-03-31 10:06:59 +02001302 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001303
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001304 /* Dummy packets require the TID to be management */
1305 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001306
1307 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001308 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001309 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001310
Ido Yariv990f5de2011-03-31 10:06:59 +02001311 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001312}
1313
Ido Yariv990f5de2011-03-31 10:06:59 +02001314
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001315#ifdef CONFIG_PM
Luciano Coelho22479972012-05-16 06:00:00 +03001316static int
1317wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001318{
1319 int num_fields = 0, in_field = 0, fields_size = 0;
1320 int i, pattern_len = 0;
1321
1322 if (!p->mask) {
1323 wl1271_warning("No mask in WoWLAN pattern");
1324 return -EINVAL;
1325 }
1326
1327 /*
1328 * The pattern is broken up into segments of bytes at different offsets
1329 * that need to be checked by the FW filter. Each segment is called
1330 * a field in the FW API. We verify that the total number of fields
1331 * required for this pattern won't exceed FW limits (8)
1332 * as well as the total fields buffer won't exceed the FW limit.
1333 * Note that if there's a pattern which crosses Ethernet/IP header
1334 * boundary a new field is required.
1335 */
1336 for (i = 0; i < p->pattern_len; i++) {
1337 if (test_bit(i, (unsigned long *)p->mask)) {
1338 if (!in_field) {
1339 in_field = 1;
1340 pattern_len = 1;
1341 } else {
1342 if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1343 num_fields++;
1344 fields_size += pattern_len +
1345 RX_FILTER_FIELD_OVERHEAD;
1346 pattern_len = 1;
1347 } else
1348 pattern_len++;
1349 }
1350 } else {
1351 if (in_field) {
1352 in_field = 0;
1353 fields_size += pattern_len +
1354 RX_FILTER_FIELD_OVERHEAD;
1355 num_fields++;
1356 }
1357 }
1358 }
1359
1360 if (in_field) {
1361 fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
1362 num_fields++;
1363 }
1364
1365 if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
1366 wl1271_warning("RX Filter too complex. Too many segments");
1367 return -EINVAL;
1368 }
1369
1370 if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
1371 wl1271_warning("RX filter pattern is too big");
1372 return -E2BIG;
1373 }
1374
1375 return 0;
1376}
1377
Eyal Shapiraa6eab0c2012-03-14 06:32:07 +02001378struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
1379{
1380 return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
1381}
1382
1383void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
1384{
1385 int i;
1386
1387 if (filter == NULL)
1388 return;
1389
1390 for (i = 0; i < filter->num_fields; i++)
1391 kfree(filter->fields[i].pattern);
1392
1393 kfree(filter);
1394}
1395
1396int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
1397 u16 offset, u8 flags,
1398 u8 *pattern, u8 len)
1399{
1400 struct wl12xx_rx_filter_field *field;
1401
1402 if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
1403 wl1271_warning("Max fields per RX filter. can't alloc another");
1404 return -EINVAL;
1405 }
1406
1407 field = &filter->fields[filter->num_fields];
1408
1409 field->pattern = kzalloc(len, GFP_KERNEL);
1410 if (!field->pattern) {
1411 wl1271_warning("Failed to allocate RX filter pattern");
1412 return -ENOMEM;
1413 }
1414
1415 filter->num_fields++;
1416
1417 field->offset = cpu_to_le16(offset);
1418 field->flags = flags;
1419 field->len = len;
1420 memcpy(field->pattern, pattern, len);
1421
1422 return 0;
1423}
1424
1425int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
1426{
1427 int i, fields_size = 0;
1428
1429 for (i = 0; i < filter->num_fields; i++)
1430 fields_size += filter->fields[i].len +
1431 sizeof(struct wl12xx_rx_filter_field) -
1432 sizeof(u8 *);
1433
1434 return fields_size;
1435}
1436
1437void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
1438 u8 *buf)
1439{
1440 int i;
1441 struct wl12xx_rx_filter_field *field;
1442
1443 for (i = 0; i < filter->num_fields; i++) {
1444 field = (struct wl12xx_rx_filter_field *)buf;
1445
1446 field->offset = filter->fields[i].offset;
1447 field->flags = filter->fields[i].flags;
1448 field->len = filter->fields[i].len;
1449
1450 memcpy(&field->pattern, filter->fields[i].pattern, field->len);
1451 buf += sizeof(struct wl12xx_rx_filter_field) -
1452 sizeof(u8 *) + field->len;
1453 }
1454}
1455
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001456/*
1457 * Allocates an RX filter returned through f
1458 * which needs to be freed using rx_filter_free()
1459 */
Luciano Coelho22479972012-05-16 06:00:00 +03001460static int wl1271_convert_wowlan_pattern_to_rx_filter(
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001461 struct cfg80211_wowlan_trig_pkt_pattern *p,
1462 struct wl12xx_rx_filter **f)
1463{
1464 int i, j, ret = 0;
1465 struct wl12xx_rx_filter *filter;
1466 u16 offset;
1467 u8 flags, len;
1468
1469 filter = wl1271_rx_filter_alloc();
1470 if (!filter) {
1471 wl1271_warning("Failed to alloc rx filter");
1472 ret = -ENOMEM;
1473 goto err;
1474 }
1475
1476 i = 0;
1477 while (i < p->pattern_len) {
1478 if (!test_bit(i, (unsigned long *)p->mask)) {
1479 i++;
1480 continue;
1481 }
1482
1483 for (j = i; j < p->pattern_len; j++) {
1484 if (!test_bit(j, (unsigned long *)p->mask))
1485 break;
1486
1487 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
1488 j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
1489 break;
1490 }
1491
1492 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1493 offset = i;
1494 flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
1495 } else {
1496 offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
1497 flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
1498 }
1499
1500 len = j - i;
1501
1502 ret = wl1271_rx_filter_alloc_field(filter,
1503 offset,
1504 flags,
1505 &p->pattern[i], len);
1506 if (ret)
1507 goto err;
1508
1509 i = j;
1510 }
1511
1512 filter->action = FILTER_SIGNAL;
1513
1514 *f = filter;
1515 return 0;
1516
1517err:
1518 wl1271_rx_filter_free(filter);
1519 *f = NULL;
1520
1521 return ret;
1522}
1523
1524static int wl1271_configure_wowlan(struct wl1271 *wl,
1525 struct cfg80211_wowlan *wow)
1526{
1527 int i, ret;
1528
1529 if (!wow || wow->any || !wow->n_patterns) {
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001530 ret = wl1271_acx_default_rx_filter_enable(wl, 0,
1531 FILTER_SIGNAL);
1532 if (ret)
1533 goto out;
1534
1535 ret = wl1271_rx_filter_clear_all(wl);
1536 if (ret)
1537 goto out;
1538
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001539 return 0;
1540 }
1541
1542 if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
1543 return -EINVAL;
1544
1545 /* Validate all incoming patterns before clearing current FW state */
1546 for (i = 0; i < wow->n_patterns; i++) {
1547 ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
1548 if (ret) {
1549 wl1271_warning("Bad wowlan pattern %d", i);
1550 return ret;
1551 }
1552 }
1553
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001554 ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1555 if (ret)
1556 goto out;
1557
1558 ret = wl1271_rx_filter_clear_all(wl);
1559 if (ret)
1560 goto out;
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001561
1562 /* Translate WoWLAN patterns into filters */
1563 for (i = 0; i < wow->n_patterns; i++) {
1564 struct cfg80211_wowlan_trig_pkt_pattern *p;
1565 struct wl12xx_rx_filter *filter = NULL;
1566
1567 p = &wow->patterns[i];
1568
1569 ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
1570 if (ret) {
1571 wl1271_warning("Failed to create an RX filter from "
1572 "wowlan pattern %d", i);
1573 goto out;
1574 }
1575
1576 ret = wl1271_rx_filter_enable(wl, i, 1, filter);
1577
1578 wl1271_rx_filter_free(filter);
1579 if (ret)
1580 goto out;
1581 }
1582
1583 ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
1584
1585out:
1586 return ret;
1587}
1588
Eyal Shapiradae728f2012-02-02 12:03:39 +02001589static int wl1271_configure_suspend_sta(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001590 struct wl12xx_vif *wlvif,
1591 struct cfg80211_wowlan *wow)
Eyal Shapiradae728f2012-02-02 12:03:39 +02001592{
1593 int ret = 0;
1594
Eyal Shapiradae728f2012-02-02 12:03:39 +02001595 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001596 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001597
1598 ret = wl1271_ps_elp_wakeup(wl);
1599 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001600 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001601
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001602 ret = wl1271_configure_wowlan(wl, wow);
1603 if (ret < 0)
1604 goto out_sleep;
1605
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001606 if ((wl->conf.conn.suspend_wake_up_event ==
1607 wl->conf.conn.wake_up_event) &&
1608 (wl->conf.conn.suspend_listen_interval ==
1609 wl->conf.conn.listen_interval))
1610 goto out_sleep;
1611
Eyal Shapiradae728f2012-02-02 12:03:39 +02001612 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1613 wl->conf.conn.suspend_wake_up_event,
1614 wl->conf.conn.suspend_listen_interval);
1615
1616 if (ret < 0)
1617 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1618
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001619out_sleep:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001620 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001621out:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001622 return ret;
1623
1624}
Eliad Peller94390642011-05-13 11:57:13 +03001625
Eliad Peller0603d892011-10-05 11:55:51 +02001626static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1627 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001628{
Eliad Pellere85d1622011-06-27 13:06:43 +03001629 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001630
Eliad Peller53d40d02011-10-10 10:13:02 +02001631 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001632 goto out;
Eliad Pellere85d1622011-06-27 13:06:43 +03001633
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001634 ret = wl1271_ps_elp_wakeup(wl);
1635 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001636 goto out;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001637
Eliad Peller0603d892011-10-05 11:55:51 +02001638 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001639
1640 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001641out:
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001642 return ret;
1643
1644}
1645
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001646static int wl1271_configure_suspend(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001647 struct wl12xx_vif *wlvif,
1648 struct cfg80211_wowlan *wow)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001649{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001650 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001651 return wl1271_configure_suspend_sta(wl, wlvif, wow);
Eliad Peller536129c2011-10-05 11:55:45 +02001652 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001653 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654 return 0;
1655}
1656
Luciano Coelho8f6ac532013-05-04 01:06:11 +03001657static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001658{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001659 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001660 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001661 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001662
Eyal Shapiradae728f2012-02-02 12:03:39 +02001663 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001664 return;
1665
Eliad Pellerd49524d2012-08-01 18:44:22 +03001666 if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1667 return;
1668
Eliad Peller94390642011-05-13 11:57:13 +03001669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001671 return;
Eliad Peller94390642011-05-13 11:57:13 +03001672
Eyal Shapiradae728f2012-02-02 12:03:39 +02001673 if (is_sta) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001674 wl1271_configure_wowlan(wl, NULL);
1675
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001676 if ((wl->conf.conn.suspend_wake_up_event ==
1677 wl->conf.conn.wake_up_event) &&
1678 (wl->conf.conn.suspend_listen_interval ==
1679 wl->conf.conn.listen_interval))
1680 goto out_sleep;
1681
Eyal Shapiradae728f2012-02-02 12:03:39 +02001682 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1683 wl->conf.conn.wake_up_event,
1684 wl->conf.conn.listen_interval);
1685
1686 if (ret < 0)
1687 wl1271_error("resume: wake up conditions failed: %d",
1688 ret);
1689
1690 } else if (is_ap) {
1691 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1692 }
Eliad Peller94390642011-05-13 11:57:13 +03001693
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001694out_sleep:
Eliad Peller94390642011-05-13 11:57:13 +03001695 wl1271_ps_elp_sleep(wl);
Eliad Peller94390642011-05-13 11:57:13 +03001696}
1697
Eliad Peller402e48612011-05-13 11:57:09 +03001698static int wl1271_op_suspend(struct ieee80211_hw *hw,
1699 struct cfg80211_wowlan *wow)
1700{
1701 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001702 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001703 int ret;
1704
Eliad Peller402e48612011-05-13 11:57:09 +03001705 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001706 WARN_ON(!wow);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001707
Arik Nemtsov96caded2012-06-21 18:10:47 +03001708 /* we want to perform the recovery before suspending */
1709 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1710 wl1271_warning("postponing suspend to perform recovery");
1711 return -EBUSY;
1712 }
1713
Arik Nemtsovb9239b62012-02-28 00:41:33 +02001714 wl1271_tx_flush(wl);
1715
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001716 mutex_lock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001717 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001718 wl12xx_for_each_wlvif(wl, wlvif) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001719 ret = wl1271_configure_suspend(wl, wlvif, wow);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001720 if (ret < 0) {
Dan Carpentercd840f62012-04-16 13:57:02 +03001721 mutex_unlock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001722 wl1271_warning("couldn't prepare device to suspend");
1723 return ret;
1724 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001725 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001726 mutex_unlock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001727 /* flush any remaining work */
1728 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001729
1730 /*
1731 * disable and re-enable interrupts in order to flush
1732 * the threaded_irq
1733 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001734 wlcore_disable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001735
1736 /*
1737 * set suspended flag to avoid triggering a new threaded_irq
1738 * work. no need for spinlock as interrupts are disabled.
1739 */
1740 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1741
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001742 wlcore_enable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001743 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001744 flush_delayed_work(&wl->elp_work);
1745
Eliad Peller402e48612011-05-13 11:57:09 +03001746 return 0;
1747}
1748
1749static int wl1271_op_resume(struct ieee80211_hw *hw)
1750{
1751 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001752 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001753 unsigned long flags;
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001754 bool run_irq_work = false, pending_recovery;
Arik Nemtsov725b8272012-06-21 18:10:52 +03001755 int ret;
Eliad Peller4a859df2011-06-06 12:21:52 +03001756
Eliad Peller402e48612011-05-13 11:57:09 +03001757 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1758 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001759 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001760
1761 /*
1762 * re-enable irq_work enqueuing, and call irq_work directly if
1763 * there is a pending work.
1764 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001765 spin_lock_irqsave(&wl->wl_lock, flags);
1766 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1767 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1768 run_irq_work = true;
1769 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001770
Arik Nemtsov725b8272012-06-21 18:10:52 +03001771 mutex_lock(&wl->mutex);
1772
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001773 /* test the recovery flag before calling any SDIO functions */
1774 pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
1775 &wl->flags);
1776
Eliad Peller4a859df2011-06-06 12:21:52 +03001777 if (run_irq_work) {
1778 wl1271_debug(DEBUG_MAC80211,
1779 "run postponed irq_work directly");
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001780
1781 /* don't talk to the HW if recovery is pending */
Arik Nemtsov725b8272012-06-21 18:10:52 +03001782 if (!pending_recovery) {
1783 ret = wlcore_irq_locked(wl);
1784 if (ret)
1785 wl12xx_queue_recovery_work(wl);
1786 }
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001787
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001788 wlcore_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001789 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001790
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001791 if (pending_recovery) {
1792 wl1271_warning("queuing forgotten recovery on resume");
1793 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1794 goto out;
1795 }
1796
Eliad Peller6e8cd332011-10-10 10:13:13 +02001797 wl12xx_for_each_wlvif(wl, wlvif) {
1798 wl1271_configure_resume(wl, wlvif);
1799 }
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001800
1801out:
Eliad Pellerff91afc2011-06-06 12:21:53 +03001802 wl->wow_enabled = false;
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001803 mutex_unlock(&wl->mutex);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001804
Eliad Peller402e48612011-05-13 11:57:09 +03001805 return 0;
1806}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001807#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001808
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809static int wl1271_op_start(struct ieee80211_hw *hw)
1810{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001811 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1812
1813 /*
1814 * We have to delay the booting of the hardware because
1815 * we need to know the local MAC address before downloading and
1816 * initializing the firmware. The MAC address cannot be changed
1817 * after boot, and without the proper MAC address, the firmware
1818 * will not function properly.
1819 *
1820 * The MAC address is first known when the corresponding interface
1821 * is added. That is where we will initialize the hardware.
1822 */
1823
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001824 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001825}
1826
Ido Yarivc24ec832012-06-26 21:08:58 +03001827static void wlcore_op_stop_locked(struct wl1271 *wl)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001828{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001829 int i;
1830
Ido Yariv4cc53382012-07-24 19:18:49 +03001831 if (wl->state == WLCORE_STATE_OFF) {
Ido Yarivb666bb72012-05-21 01:10:11 +03001832 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
1833 &wl->flags))
1834 wlcore_enable_interrupts(wl);
1835
Eliad Peller10c8cd02011-10-10 10:13:06 +02001836 return;
1837 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001838
Eliad Pellerbaf62772011-10-10 10:12:52 +02001839 /*
1840 * this must be before the cancel_work calls below, so that the work
1841 * functions don't perform further work.
1842 */
Ido Yariv4cc53382012-07-24 19:18:49 +03001843 wl->state = WLCORE_STATE_OFF;
Ido Yarivc24ec832012-06-26 21:08:58 +03001844
1845 /*
1846 * Use the nosync variant to disable interrupts, so the mutex could be
1847 * held while doing so without deadlocking.
1848 */
1849 wlcore_disable_interrupts_nosync(wl);
1850
Eliad Peller10c8cd02011-10-10 10:13:06 +02001851 mutex_unlock(&wl->mutex);
1852
Ido Yarivc24ec832012-06-26 21:08:58 +03001853 wlcore_synchronize_interrupts(wl);
Eliad Peller6dbc5fc2012-07-29 14:37:29 +03001854 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1855 cancel_work_sync(&wl->recovery_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001856 wl1271_flush_deferred_work(wl);
1857 cancel_delayed_work_sync(&wl->scan_complete_work);
1858 cancel_work_sync(&wl->netstack_work);
1859 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001860 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001861 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001862
1863 /* let's notify MAC80211 about the remaining pending TX frames */
Eliad Pellerbaf62772011-10-10 10:12:52 +02001864 mutex_lock(&wl->mutex);
Arik Nemtsovd935e382012-11-27 08:44:53 +02001865 wl12xx_tx_reset(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001866
1867 wl1271_power_off(wl);
Ido Yarivb666bb72012-05-21 01:10:11 +03001868 /*
1869 * In case a recovery was scheduled, interrupts were disabled to avoid
1870 * an interrupt storm. Now that the power is down, it is safe to
1871 * re-enable interrupts to balance the disable depth
1872 */
1873 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1874 wlcore_enable_interrupts(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001875
1876 wl->band = IEEE80211_BAND_2GHZ;
1877
1878 wl->rx_counter = 0;
1879 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001880 wl->channel_type = NL80211_CHAN_NO_HT;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001881 wl->tx_blocks_available = 0;
1882 wl->tx_allocated_blocks = 0;
1883 wl->tx_results_count = 0;
1884 wl->tx_packets_count = 0;
1885 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001886 wl->ap_fw_ps_map = 0;
1887 wl->ap_ps_map = 0;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001888 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001889 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1890 memset(wl->links_map, 0, sizeof(wl->links_map));
1891 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Eliad Peller978cd3a2012-11-22 18:06:21 +02001892 memset(wl->session_ids, 0, sizeof(wl->session_ids));
Eliad Pellerbaf62772011-10-10 10:12:52 +02001893 wl->active_sta_count = 0;
Arik Nemtsov9a100962012-11-28 11:42:42 +02001894 wl->active_link_count = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001895
1896 /* The system link is always allocated */
Arik Nemtsov9ebcb232012-11-27 08:44:59 +02001897 wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0;
1898 wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001899 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1900
1901 /*
1902 * this is performed after the cancel_work calls and the associated
1903 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1904 * get executed before all these vars have been reset.
1905 */
1906 wl->flags = 0;
1907
1908 wl->tx_blocks_freed = 0;
1909
1910 for (i = 0; i < NUM_TX_QUEUES; i++) {
1911 wl->tx_pkts_freed[i] = 0;
1912 wl->tx_allocated_pkts[i] = 0;
1913 }
1914
1915 wl1271_debugfs_reset(wl);
1916
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001917 kfree(wl->fw_status_1);
1918 wl->fw_status_1 = NULL;
1919 wl->fw_status_2 = NULL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001920 kfree(wl->tx_res_if);
1921 wl->tx_res_if = NULL;
1922 kfree(wl->target_mem_map);
1923 wl->target_mem_map = NULL;
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02001924
1925 /*
1926 * FW channels must be re-calibrated after recovery,
1927 * clear the last Reg-Domain channel configuration.
1928 */
1929 memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));
Ido Yarivc24ec832012-06-26 21:08:58 +03001930}
1931
1932static void wlcore_op_stop(struct ieee80211_hw *hw)
1933{
1934 struct wl1271 *wl = hw->priv;
1935
1936 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1937
1938 mutex_lock(&wl->mutex);
1939
1940 wlcore_op_stop_locked(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001941
1942 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001943}
1944
Eliad Pellerc50a2822012-11-22 18:06:19 +02001945static void wlcore_channel_switch_work(struct work_struct *work)
1946{
1947 struct delayed_work *dwork;
1948 struct wl1271 *wl;
1949 struct ieee80211_vif *vif;
1950 struct wl12xx_vif *wlvif;
1951 int ret;
1952
1953 dwork = container_of(work, struct delayed_work, work);
1954 wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work);
1955 wl = wlvif->wl;
1956
1957 wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id);
1958
1959 mutex_lock(&wl->mutex);
1960
1961 if (unlikely(wl->state != WLCORE_STATE_ON))
1962 goto out;
1963
1964 /* check the channel switch is still ongoing */
1965 if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags))
1966 goto out;
1967
1968 vif = wl12xx_wlvif_to_vif(wlvif);
1969 ieee80211_chswitch_done(vif, false);
1970
1971 ret = wl1271_ps_elp_wakeup(wl);
1972 if (ret < 0)
1973 goto out;
1974
1975 wl12xx_cmd_stop_channel_switch(wl, wlvif);
1976
1977 wl1271_ps_elp_sleep(wl);
1978out:
1979 mutex_unlock(&wl->mutex);
1980}
1981
1982static void wlcore_connection_loss_work(struct work_struct *work)
1983{
1984 struct delayed_work *dwork;
1985 struct wl1271 *wl;
1986 struct ieee80211_vif *vif;
1987 struct wl12xx_vif *wlvif;
1988
1989 dwork = container_of(work, struct delayed_work, work);
1990 wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work);
1991 wl = wlvif->wl;
1992
1993 wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id);
1994
1995 mutex_lock(&wl->mutex);
1996
1997 if (unlikely(wl->state != WLCORE_STATE_ON))
1998 goto out;
1999
2000 /* Call mac80211 connection loss */
2001 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
2002 goto out;
2003
2004 vif = wl12xx_wlvif_to_vif(wlvif);
2005 ieee80211_connection_loss(vif);
2006out:
2007 mutex_unlock(&wl->mutex);
2008}
2009
Eliad Pellere5a359f2011-10-10 10:13:15 +02002010static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
2011{
2012 u8 policy = find_first_zero_bit(wl->rate_policies_map,
2013 WL12XX_MAX_RATE_POLICIES);
2014 if (policy >= WL12XX_MAX_RATE_POLICIES)
2015 return -EBUSY;
2016
2017 __set_bit(policy, wl->rate_policies_map);
2018 *idx = policy;
2019 return 0;
2020}
2021
2022static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
2023{
2024 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
2025 return;
2026
2027 __clear_bit(*idx, wl->rate_policies_map);
2028 *idx = WL12XX_MAX_RATE_POLICIES;
2029}
2030
Eliad Peller001e39a2012-08-16 13:52:47 +03002031static int wlcore_allocate_klv_template(struct wl1271 *wl, u8 *idx)
2032{
2033 u8 policy = find_first_zero_bit(wl->klv_templates_map,
2034 WLCORE_MAX_KLV_TEMPLATES);
2035 if (policy >= WLCORE_MAX_KLV_TEMPLATES)
2036 return -EBUSY;
2037
2038 __set_bit(policy, wl->klv_templates_map);
2039 *idx = policy;
2040 return 0;
2041}
2042
2043static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx)
2044{
2045 if (WARN_ON(*idx >= WLCORE_MAX_KLV_TEMPLATES))
2046 return;
2047
2048 __clear_bit(*idx, wl->klv_templates_map);
2049 *idx = WLCORE_MAX_KLV_TEMPLATES;
2050}
2051
Eliad Peller536129c2011-10-05 11:55:45 +02002052static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002053{
Eliad Peller536129c2011-10-05 11:55:45 +02002054 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002055 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02002056 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03002057 return WL1271_ROLE_P2P_GO;
2058 else
2059 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002060
2061 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02002062 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03002063 return WL1271_ROLE_P2P_CL;
2064 else
2065 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002066
Eliad Peller227e81e2011-08-14 13:17:26 +03002067 case BSS_TYPE_IBSS:
2068 return WL1271_ROLE_IBSS;
2069
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002070 default:
Eliad Peller536129c2011-10-05 11:55:45 +02002071 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002072 }
2073 return WL12XX_INVALID_ROLE_TYPE;
2074}
2075
Eliad Peller83587502011-10-10 10:12:53 +02002076static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002077{
Eliad Pellere936bbe2011-10-05 11:55:56 +02002078 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002079 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002080
Eliad Peller48e93e42011-10-10 10:12:58 +02002081 /* clear everything but the persistent data */
2082 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02002083
2084 switch (ieee80211_vif_type_p2p(vif)) {
2085 case NL80211_IFTYPE_P2P_CLIENT:
2086 wlvif->p2p = 1;
2087 /* fall-through */
2088 case NL80211_IFTYPE_STATION:
2089 wlvif->bss_type = BSS_TYPE_STA_BSS;
2090 break;
2091 case NL80211_IFTYPE_ADHOC:
2092 wlvif->bss_type = BSS_TYPE_IBSS;
2093 break;
2094 case NL80211_IFTYPE_P2P_GO:
2095 wlvif->p2p = 1;
2096 /* fall-through */
2097 case NL80211_IFTYPE_AP:
2098 wlvif->bss_type = BSS_TYPE_AP_BSS;
2099 break;
2100 default:
2101 wlvif->bss_type = MAX_BSS_TYPE;
2102 return -EOPNOTSUPP;
2103 }
2104
Eliad Peller0603d892011-10-05 11:55:51 +02002105 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002106 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002107 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002108
Eliad Pellere936bbe2011-10-05 11:55:56 +02002109 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2110 wlvif->bss_type == BSS_TYPE_IBSS) {
2111 /* init sta/ibss data */
2112 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002113 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2114 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2115 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Peller001e39a2012-08-16 13:52:47 +03002116 wlcore_allocate_klv_template(wl, &wlvif->sta.klv_template_id);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002117 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
2118 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
2119 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002120 } else {
2121 /* init ap data */
2122 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2123 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002124 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2125 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2126 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2127 wl12xx_allocate_rate_policy(wl,
2128 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller42ec1f82012-11-20 13:20:08 +02002129 wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002130 /*
2131 * TODO: check if basic_rate shouldn't be
2132 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2133 * instead (the same thing for STA above).
2134 */
Eliad Peller42ec1f82012-11-20 13:20:08 +02002135 wlvif->basic_rate = CONF_TX_ENABLED_RATES;
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002136 /* TODO: this seems to be used only for STA, check it */
Eliad Peller42ec1f82012-11-20 13:20:08 +02002137 wlvif->rate_set = CONF_TX_ENABLED_RATES;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002138 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002139
Eliad Peller83587502011-10-10 10:12:53 +02002140 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2141 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller6a899792011-10-05 11:55:58 +02002142 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2143
Eliad Peller1b92f152011-10-10 10:13:09 +02002144 /*
2145 * mac80211 configures some values globally, while we treat them
2146 * per-interface. thus, on init, we have to copy them from wl
2147 */
2148 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002149 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002150 wlvif->power_level = wl->power_level;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002151 wlvif->channel_type = wl->channel_type;
Eliad Peller1b92f152011-10-10 10:13:09 +02002152
Eliad Peller9eb599e2011-10-10 10:12:59 +02002153 INIT_WORK(&wlvif->rx_streaming_enable_work,
2154 wl1271_rx_streaming_enable_work);
2155 INIT_WORK(&wlvif->rx_streaming_disable_work,
2156 wl1271_rx_streaming_disable_work);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002157 INIT_DELAYED_WORK(&wlvif->channel_switch_work,
2158 wlcore_channel_switch_work);
2159 INIT_DELAYED_WORK(&wlvif->connection_loss_work,
2160 wlcore_connection_loss_work);
Eliad Peller87627212011-10-10 10:12:54 +02002161 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002162
Eliad Peller9eb599e2011-10-10 10:12:59 +02002163 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2164 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002165 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002166}
2167
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002168static int wl12xx_init_fw(struct wl1271 *wl)
Eliad Peller1d095472011-10-10 10:12:49 +02002169{
2170 int retries = WL1271_BOOT_RETRIES;
2171 bool booted = false;
2172 struct wiphy *wiphy = wl->hw->wiphy;
2173 int ret;
2174
2175 while (retries) {
2176 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02002177 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02002178 if (ret < 0)
2179 goto power_off;
2180
Luciano Coelhodd5512e2012-04-11 11:03:14 +03002181 ret = wl->ops->boot(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02002182 if (ret < 0)
2183 goto power_off;
2184
2185 ret = wl1271_hw_init(wl);
2186 if (ret < 0)
2187 goto irq_disable;
2188
2189 booted = true;
2190 break;
2191
2192irq_disable:
2193 mutex_unlock(&wl->mutex);
2194 /* Unlocking the mutex in the middle of handling is
2195 inherently unsafe. In this case we deem it safe to do,
2196 because we need to let any possibly pending IRQ out of
Ido Yariv4cc53382012-07-24 19:18:49 +03002197 the system (and while we are WLCORE_STATE_OFF the IRQ
Eliad Peller1d095472011-10-10 10:12:49 +02002198 work function will not do anything.) Also, any other
2199 possible concurrent operations will fail due to the
2200 current state, hence the wl1271 struct should be safe. */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03002201 wlcore_disable_interrupts(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02002202 wl1271_flush_deferred_work(wl);
2203 cancel_work_sync(&wl->netstack_work);
2204 mutex_lock(&wl->mutex);
2205power_off:
2206 wl1271_power_off(wl);
2207 }
2208
2209 if (!booted) {
2210 wl1271_error("firmware boot failed despite %d retries",
2211 WL1271_BOOT_RETRIES);
2212 goto out;
2213 }
2214
2215 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2216
2217 /* update hw/fw version info in wiphy struct */
2218 wiphy->hw_version = wl->chip.id;
2219 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2220 sizeof(wiphy->fw_version));
2221
2222 /*
2223 * Now we know if 11a is supported (info from the NVS), so disable
2224 * 11a channels if not supported
2225 */
2226 if (!wl->enable_11a)
2227 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2228
2229 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2230 wl->enable_11a ? "" : "not ");
2231
Ido Yariv4cc53382012-07-24 19:18:49 +03002232 wl->state = WLCORE_STATE_ON;
Eliad Peller1d095472011-10-10 10:12:49 +02002233out:
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002234 return ret;
Eliad Peller1d095472011-10-10 10:12:49 +02002235}
2236
Eliad Peller92e712d2011-12-18 20:25:43 +02002237static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2238{
2239 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2240}
2241
Eliad Peller4549d092012-02-06 13:07:52 +02002242/*
2243 * Check whether a fw switch (i.e. moving from one loaded
2244 * fw to another) is needed. This function is also responsible
2245 * for updating wl->last_vif_count, so it must be called before
2246 * loading a non-plt fw (so the correct fw (single-role/multi-role)
2247 * will be used).
2248 */
2249static bool wl12xx_need_fw_change(struct wl1271 *wl,
2250 struct vif_counter_data vif_counter_data,
2251 bool add)
2252{
2253 enum wl12xx_fw_type current_fw = wl->fw_type;
2254 u8 vif_count = vif_counter_data.counter;
2255
2256 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
2257 return false;
2258
2259 /* increase the vif count if this is a new vif */
2260 if (add && !vif_counter_data.cur_vif_running)
2261 vif_count++;
2262
2263 wl->last_vif_count = vif_count;
2264
2265 /* no need for fw change if the device is OFF */
Ido Yariv4cc53382012-07-24 19:18:49 +03002266 if (wl->state == WLCORE_STATE_OFF)
Eliad Peller4549d092012-02-06 13:07:52 +02002267 return false;
2268
Eliad Peller9b1a0a72012-07-25 14:22:21 +03002269 /* no need for fw change if a single fw is used */
2270 if (!wl->mr_fw_name)
2271 return false;
2272
Eliad Peller4549d092012-02-06 13:07:52 +02002273 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2274 return true;
2275 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2276 return true;
2277
2278 return false;
2279}
2280
Eliad Peller3dee4392012-02-06 12:47:56 +02002281/*
2282 * Enter "forced psm". Make sure the sta is in psm against the ap,
2283 * to make the fw switch a bit more disconnection-persistent.
2284 */
2285static void wl12xx_force_active_psm(struct wl1271 *wl)
2286{
2287 struct wl12xx_vif *wlvif;
2288
2289 wl12xx_for_each_wlvif_sta(wl, wlvif) {
2290 wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
2291 }
2292}
2293
Arik Nemtsov1c33db72012-11-30 00:48:03 +02002294struct wlcore_hw_queue_iter_data {
2295 unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)];
2296 /* current vif */
2297 struct ieee80211_vif *vif;
2298 /* is the current vif among those iterated */
2299 bool cur_running;
2300};
2301
2302static void wlcore_hw_queue_iter(void *data, u8 *mac,
2303 struct ieee80211_vif *vif)
2304{
2305 struct wlcore_hw_queue_iter_data *iter_data = data;
2306
2307 if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))
2308 return;
2309
2310 if (iter_data->cur_running || vif == iter_data->vif) {
2311 iter_data->cur_running = true;
2312 return;
2313 }
2314
2315 __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map);
2316}
2317
2318static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,
2319 struct wl12xx_vif *wlvif)
2320{
2321 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2322 struct wlcore_hw_queue_iter_data iter_data = {};
2323 int i, q_base;
2324
2325 iter_data.vif = vif;
2326
2327 /* mark all bits taken by active interfaces */
2328 ieee80211_iterate_active_interfaces_atomic(wl->hw,
2329 IEEE80211_IFACE_ITER_RESUME_ALL,
2330 wlcore_hw_queue_iter, &iter_data);
2331
2332 /* the current vif is already running in mac80211 (resume/recovery) */
2333 if (iter_data.cur_running) {
2334 wlvif->hw_queue_base = vif->hw_queue[0];
2335 wl1271_debug(DEBUG_MAC80211,
2336 "using pre-allocated hw queue base %d",
2337 wlvif->hw_queue_base);
2338
2339 /* interface type might have changed type */
2340 goto adjust_cab_queue;
2341 }
2342
2343 q_base = find_first_zero_bit(iter_data.hw_queue_map,
2344 WLCORE_NUM_MAC_ADDRESSES);
2345 if (q_base >= WLCORE_NUM_MAC_ADDRESSES)
2346 return -EBUSY;
2347
2348 wlvif->hw_queue_base = q_base * NUM_TX_QUEUES;
2349 wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d",
2350 wlvif->hw_queue_base);
2351
2352 for (i = 0; i < NUM_TX_QUEUES; i++) {
2353 wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0;
2354 /* register hw queues in mac80211 */
2355 vif->hw_queue[i] = wlvif->hw_queue_base + i;
2356 }
2357
2358adjust_cab_queue:
2359 /* the last places are reserved for cab queues per interface */
2360 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2361 vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES +
2362 wlvif->hw_queue_base / NUM_TX_QUEUES;
2363 else
2364 vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
2365
2366 return 0;
2367}
2368
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002369static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2370 struct ieee80211_vif *vif)
2371{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002373 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4549d092012-02-06 13:07:52 +02002374 struct vif_counter_data vif_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002376 u8 role_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377
Johannes Bergea086352012-01-19 09:29:58 +01002378 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2379 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002380
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002381 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002382 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002383
Eliad Peller4549d092012-02-06 13:07:52 +02002384 wl12xx_get_vif_count(hw, vif, &vif_count);
2385
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002387 ret = wl1271_ps_elp_wakeup(wl);
2388 if (ret < 0)
2389 goto out_unlock;
2390
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002391 /*
2392 * in some very corner case HW recovery scenarios its possible to
2393 * get here before __wl1271_op_remove_interface is complete, so
2394 * opt out if that is the case.
2395 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002396 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2397 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002398 ret = -EBUSY;
2399 goto out;
2400 }
2401
Eliad Peller3fcdab72012-02-06 12:47:54 +02002402
Eliad Peller83587502011-10-10 10:12:53 +02002403 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002404 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002405 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002406
Eliad Peller252efa42011-10-05 11:56:00 +02002407 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002408 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002409 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2410 ret = -EINVAL;
2411 goto out;
2412 }
Eliad Peller1d095472011-10-10 10:12:49 +02002413
Arik Nemtsov1c33db72012-11-30 00:48:03 +02002414 ret = wlcore_allocate_hw_queue_base(wl, wlvif);
2415 if (ret < 0)
2416 goto out;
2417
Eliad Peller4549d092012-02-06 13:07:52 +02002418 if (wl12xx_need_fw_change(wl, vif_count, true)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002419 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002420 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002421 mutex_unlock(&wl->mutex);
2422 wl1271_recovery_work(&wl->recovery_work);
2423 return 0;
2424 }
2425
Eliad Peller784f6942011-10-05 11:55:39 +02002426 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002427 * TODO: after the nvs issue will be solved, move this block
2428 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002429 */
Ido Yariv4cc53382012-07-24 19:18:49 +03002430 if (wl->state == WLCORE_STATE_OFF) {
Eliad Peller1d095472011-10-10 10:12:49 +02002431 /*
2432 * we still need this in order to configure the fw
2433 * while uploading the nvs
2434 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002435 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002436
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002437 ret = wl12xx_init_fw(wl);
2438 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002439 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002440 }
Eliad Peller04e80792011-08-14 13:17:09 +03002441
Eliad Peller1d095472011-10-10 10:12:49 +02002442 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2443 role_type, &wlvif->role_id);
2444 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002445 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002446
2447 ret = wl1271_init_vif_specific(wl, vif);
2448 if (ret < 0)
2449 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002450
Eliad Peller87627212011-10-10 10:12:54 +02002451 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002452 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002453
2454 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2455 wl->ap_count++;
2456 else
2457 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002458out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002459 wl1271_ps_elp_sleep(wl);
2460out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461 mutex_unlock(&wl->mutex);
2462
2463 return ret;
2464}
2465
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002466static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002467 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002468 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469{
Eliad Peller536129c2011-10-05 11:55:45 +02002470 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002471 int i, ret;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002472 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002474 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475
Eliad Peller10c8cd02011-10-10 10:13:06 +02002476 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2477 return;
2478
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002479 /* because of hardware recovery, we may get here twice */
Ido Yariv4cc53382012-07-24 19:18:49 +03002480 if (wl->state == WLCORE_STATE_OFF)
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002481 return;
2482
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002483 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002484
Eliad Pellerbaf62772011-10-10 10:12:52 +02002485 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
Eliad Pellerc50a2822012-11-22 18:06:19 +02002486 wl->scan_wlvif == wlvif) {
Arik Nemtsov55df5af2012-03-03 22:18:00 +02002487 /*
2488 * Rearm the tx watchdog just before idling scan. This
2489 * prevents just-finished scans from triggering the watchdog
2490 */
2491 wl12xx_rearm_tx_watchdog_locked(wl);
2492
Luciano Coelho08688d62010-07-08 17:50:07 +03002493 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002494 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Pellerc50a2822012-11-22 18:06:19 +02002495 wl->scan_wlvif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002496 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002497 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002498 }
2499
Eliad Peller10199752012-11-22 18:06:23 +02002500 if (wl->sched_vif == wlvif) {
2501 ieee80211_sched_scan_stopped(wl->hw);
2502 wl->sched_vif = NULL;
2503 }
2504
Arik Nemtsov5d979f32012-11-27 08:44:48 +02002505 if (wl->roc_vif == vif) {
2506 wl->roc_vif = NULL;
2507 ieee80211_remain_on_channel_expired(wl->hw);
2508 }
2509
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002510 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2511 /* disable active roles */
2512 ret = wl1271_ps_elp_wakeup(wl);
2513 if (ret < 0)
2514 goto deinit;
2515
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002516 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2517 wlvif->bss_type == BSS_TYPE_IBSS) {
2518 if (wl12xx_dev_role_started(wlvif))
2519 wl12xx_stop_dev(wl, wlvif);
Eliad Peller04e80792011-08-14 13:17:09 +03002520 }
2521
Eliad Peller0603d892011-10-05 11:55:51 +02002522 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002523 if (ret < 0)
2524 goto deinit;
2525
2526 wl1271_ps_elp_sleep(wl);
2527 }
2528deinit:
Arik Nemtsov5a996102013-03-12 17:19:43 +02002529 wl12xx_tx_reset_wlvif(wl, wlvif);
2530
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002531 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002532 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002533
2534 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2535 wlvif->bss_type == BSS_TYPE_IBSS) {
2536 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2537 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2538 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2539 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Peller001e39a2012-08-16 13:52:47 +03002540 wlcore_free_klv_template(wl, &wlvif->sta.klv_template_id);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002541 } else {
2542 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2543 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2544 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2545 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2546 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2547 wl12xx_free_rate_policy(wl,
2548 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller830be7e2012-03-19 11:32:55 +02002549 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002550 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002551
Eyal Shapira3eba4a02012-03-19 12:06:27 +02002552 dev_kfree_skb(wlvif->probereq);
2553 wlvif->probereq = NULL;
Eliad Pellere4120df2011-10-10 10:13:17 +02002554 if (wl->last_wlvif == wlvif)
2555 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002556 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002557 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002558 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002559 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002560
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002561 if (is_ap)
Eliad Pellera4e41302011-10-11 11:49:15 +02002562 wl->ap_count--;
2563 else
2564 wl->sta_count--;
2565
Arik Nemtsov42066f92012-07-10 10:45:01 +03002566 /*
2567 * Last AP, have more stations. Configure sleep auth according to STA.
2568 * Don't do thin on unintended recovery.
2569 */
2570 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) &&
2571 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags))
2572 goto unlock;
2573
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002574 if (wl->ap_count == 0 && is_ap && wl->sta_count) {
2575 u8 sta_auth = wl->conf.conn.sta_sleep_auth;
2576 /* Configure for power according to debugfs */
2577 if (sta_auth != WL1271_PSM_ILLEGAL)
2578 wl1271_acx_sleep_auth(wl, sta_auth);
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002579 /* Configure for ELP power saving */
2580 else
2581 wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
2582 }
2583
Arik Nemtsov42066f92012-07-10 10:45:01 +03002584unlock:
Eliad Pellerbaf62772011-10-10 10:12:52 +02002585 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002586
Eliad Peller9eb599e2011-10-10 10:12:59 +02002587 del_timer_sync(&wlvif->rx_streaming_timer);
2588 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2589 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002590 cancel_delayed_work_sync(&wlvif->connection_loss_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002591
Eliad Pellerbaf62772011-10-10 10:12:52 +02002592 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002593}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002594
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002595static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2596 struct ieee80211_vif *vif)
2597{
2598 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002599 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002600 struct wl12xx_vif *iter;
Eliad Peller4549d092012-02-06 13:07:52 +02002601 struct vif_counter_data vif_count;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002602
Eliad Peller4549d092012-02-06 13:07:52 +02002603 wl12xx_get_vif_count(hw, vif, &vif_count);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002604 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002605
Ido Yariv4cc53382012-07-24 19:18:49 +03002606 if (wl->state == WLCORE_STATE_OFF ||
Eliad Peller10c8cd02011-10-10 10:13:06 +02002607 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2608 goto out;
2609
Juuso Oikarinen67353292010-11-18 15:19:02 +02002610 /*
2611 * wl->vif can be null here if someone shuts down the interface
2612 * just when hardware recovery has been started.
2613 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002614 wl12xx_for_each_wlvif(wl, iter) {
2615 if (iter != wlvif)
2616 continue;
2617
Eliad Peller536129c2011-10-05 11:55:45 +02002618 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002619 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002620 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002621 WARN_ON(iter != wlvif);
Eliad Peller4549d092012-02-06 13:07:52 +02002622 if (wl12xx_need_fw_change(wl, vif_count, false)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002623 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002624 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002625 wl12xx_queue_recovery_work(wl);
Eliad Peller4549d092012-02-06 13:07:52 +02002626 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002627out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002628 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002629}
2630
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002631static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2632 struct ieee80211_vif *vif,
2633 enum nl80211_iftype new_type, bool p2p)
2634{
Eliad Peller4549d092012-02-06 13:07:52 +02002635 struct wl1271 *wl = hw->priv;
2636 int ret;
2637
2638 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002639 wl1271_op_remove_interface(hw, vif);
2640
Eliad Peller249e9692012-03-04 10:55:50 +02002641 vif->type = new_type;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002642 vif->p2p = p2p;
Eliad Peller4549d092012-02-06 13:07:52 +02002643 ret = wl1271_op_add_interface(hw, vif);
2644
2645 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2646 return ret;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002647}
2648
Eliad Peller3230f352012-11-20 13:20:01 +02002649static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002650{
2651 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002652 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002653
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002654 /*
2655 * One of the side effects of the JOIN command is that is clears
2656 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2657 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002658 * Currently the only valid scenario for JOIN during association
2659 * is on roaming, in which case we will also be given new keys.
2660 * Keep the below message for now, unless it starts bothering
2661 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002662 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002663 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002664 wl1271_info("JOIN while associated.");
2665
Eliad Peller5ec8a442012-02-02 12:22:09 +02002666 /* clear encryption type */
2667 wlvif->encryption_type = KEY_NONE;
2668
Eliad Peller227e81e2011-08-14 13:17:26 +03002669 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002670 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller18eab432012-11-20 13:20:02 +02002671 else {
2672 if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
2673 /*
2674 * TODO: this is an ugly workaround for wl12xx fw
2675 * bug - we are not able to tx/rx after the first
2676 * start_sta, so make dummy start+stop calls,
2677 * and then call start_sta again.
2678 * this should be fixed in the fw.
2679 */
2680 wl12xx_cmd_role_start_sta(wl, wlvif);
2681 wl12xx_cmd_role_stop_sta(wl, wlvif);
2682 }
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002683
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002684 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Eliad Peller18eab432012-11-20 13:20:02 +02002685 }
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002686
Eliad Peller3230f352012-11-20 13:20:01 +02002687 return ret;
2688}
2689
2690static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb,
2691 int offset)
2692{
2693 u8 ssid_len;
2694 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2695 skb->len - offset);
2696
2697 if (!ptr) {
2698 wl1271_error("No SSID in IEs!");
2699 return -ENOENT;
2700 }
2701
2702 ssid_len = ptr[1];
2703 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2704 wl1271_error("SSID is too long!");
2705 return -EINVAL;
2706 }
2707
2708 wlvif->ssid_len = ssid_len;
2709 memcpy(wlvif->ssid, ptr+2, ssid_len);
2710 return 0;
2711}
2712
2713static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
2714{
2715 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2716 struct sk_buff *skb;
2717 int ieoffset;
2718
2719 /* we currently only support setting the ssid from the ap probe req */
2720 if (wlvif->bss_type != BSS_TYPE_STA_BSS)
2721 return -EINVAL;
2722
2723 skb = ieee80211_ap_probereq_get(wl->hw, vif);
2724 if (!skb)
2725 return -EINVAL;
2726
2727 ieoffset = offsetof(struct ieee80211_mgmt,
2728 u.probe_req.variable);
2729 wl1271_ssid_set(wlvif, skb, ieoffset);
2730 dev_kfree_skb(skb);
2731
2732 return 0;
2733}
2734
2735static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
Eliad Pellerec870112012-11-20 13:20:09 +02002736 struct ieee80211_bss_conf *bss_conf,
2737 u32 sta_rate_set)
Eliad Peller3230f352012-11-20 13:20:01 +02002738{
2739 int ieoffset;
2740 int ret;
2741
2742 wlvif->aid = bss_conf->aid;
Luciano Coelhoaaabee82012-12-04 16:39:47 +02002743 wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef);
Eliad Peller3230f352012-11-20 13:20:01 +02002744 wlvif->beacon_int = bss_conf->beacon_int;
Eliad Pellerd50529c2012-11-22 18:06:20 +02002745 wlvif->wmm_enabled = bss_conf->qos;
Eliad Peller3230f352012-11-20 13:20:01 +02002746
2747 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
2748
2749 /*
2750 * with wl1271, we don't need to update the
2751 * beacon_int and dtim_period, because the firmware
2752 * updates it by itself when the first beacon is
2753 * received after a join.
2754 */
2755 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
2756 if (ret < 0)
2757 return ret;
2758
2759 /*
2760 * Get a template for hardware connection maintenance
2761 */
2762 dev_kfree_skb(wlvif->probereq);
2763 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
2764 wlvif,
2765 NULL);
2766 ieoffset = offsetof(struct ieee80211_mgmt,
2767 u.probe_req.variable);
2768 wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset);
2769
2770 /* enable the connection monitoring feature */
2771 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
2772 if (ret < 0)
2773 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002774
2775 /*
2776 * The join command disable the keep-alive mode, shut down its process,
2777 * and also clear the template config, so we need to reset it all after
2778 * the join. The acx_aid starts the keep-alive process, and the order
2779 * of the commands below is relevant.
2780 */
Eliad Peller0603d892011-10-05 11:55:51 +02002781 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002782 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002783 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002784
Eliad Peller0603d892011-10-05 11:55:51 +02002785 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002786 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002787 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002788
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002789 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002790 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002791 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002792
Eliad Peller0603d892011-10-05 11:55:51 +02002793 ret = wl1271_acx_keep_alive_config(wl, wlvif,
Eliad Peller001e39a2012-08-16 13:52:47 +03002794 wlvif->sta.klv_template_id,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002795 ACX_KEEP_ALIVE_TPL_VALID);
2796 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002797 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002798
Eliad Peller6c7b5192012-11-20 13:20:07 +02002799 /*
2800 * The default fw psm configuration is AUTO, while mac80211 default
2801 * setting is off (ACTIVE), so sync the fw with the correct value.
2802 */
2803 ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE);
Eliad Pellerec870112012-11-20 13:20:09 +02002804 if (ret < 0)
2805 return ret;
2806
2807 if (sta_rate_set) {
2808 wlvif->rate_set =
2809 wl1271_tx_enabled_rates_get(wl,
2810 sta_rate_set,
2811 wlvif->band);
2812 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
2813 if (ret < 0)
2814 return ret;
2815 }
Eliad Peller6c7b5192012-11-20 13:20:07 +02002816
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002817 return ret;
2818}
2819
Eliad Peller3230f352012-11-20 13:20:01 +02002820static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002821{
2822 int ret;
Eliad Peller3230f352012-11-20 13:20:01 +02002823 bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
2824
2825 /* make sure we are connected (sta) joined */
2826 if (sta &&
2827 !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
2828 return false;
2829
2830 /* make sure we are joined (ibss) */
2831 if (!sta &&
2832 test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))
2833 return false;
2834
2835 if (sta) {
2836 /* use defaults when not associated */
2837 wlvif->aid = 0;
2838
2839 /* free probe-request template */
2840 dev_kfree_skb(wlvif->probereq);
2841 wlvif->probereq = NULL;
2842
2843 /* disable connection monitor features */
2844 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
2845 if (ret < 0)
2846 return ret;
2847
2848 /* Disable the keep-alive feature */
2849 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
2850 if (ret < 0)
2851 return ret;
2852 }
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002853
Eliad Peller52630c52011-10-10 10:13:08 +02002854 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002855 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2856
Eliad Pellerfcab1892012-11-22 18:06:18 +02002857 wl12xx_cmd_stop_channel_switch(wl, wlvif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002858 ieee80211_chswitch_done(vif, false);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002859 cancel_delayed_work(&wlvif->channel_switch_work);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002860 }
2861
Eliad Peller4137c172012-08-16 13:32:32 +03002862 /* invalidate keep-alive template */
2863 wl1271_acx_keep_alive_config(wl, wlvif,
Eliad Peller001e39a2012-08-16 13:52:47 +03002864 wlvif->sta.klv_template_id,
Eliad Peller4137c172012-08-16 13:32:32 +03002865 ACX_KEEP_ALIVE_TPL_INVALID);
2866
Eliad Peller3230f352012-11-20 13:20:01 +02002867 return 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002868}
2869
Eliad Peller87fbcb02011-10-05 11:55:41 +02002870static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002871{
Eliad Peller1b92f152011-10-10 10:13:09 +02002872 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002873 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002874}
2875
Eliad Peller9f259c42011-10-10 10:13:12 +02002876static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2877 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002878{
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002879 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880
Eliad Peller6bd65022011-10-10 10:13:11 +02002881 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002882 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002883 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002884 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002885
Eliad Peller6bd65022011-10-10 10:13:11 +02002886 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002887 }
2888
Eliad Peller9f259c42011-10-10 10:13:12 +02002889 return 0;
2890}
2891
2892static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2893{
2894 struct wl1271 *wl = hw->priv;
2895 struct wl12xx_vif *wlvif;
2896 struct ieee80211_conf *conf = &hw->conf;
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002897 int ret = 0;
Eliad Peller9f259c42011-10-10 10:13:12 +02002898
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002899 wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
Eliad Peller9f259c42011-10-10 10:13:12 +02002900 " changed 0x%x",
Eliad Peller9f259c42011-10-10 10:13:12 +02002901 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2902 conf->power_level,
2903 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2904 changed);
2905
Eliad Peller9f259c42011-10-10 10:13:12 +02002906 mutex_lock(&wl->mutex);
2907
Eliad Peller9f259c42011-10-10 10:13:12 +02002908 if (changed & IEEE80211_CONF_CHANGE_POWER)
2909 wl->power_level = conf->power_level;
2910
Ido Yariv4cc53382012-07-24 19:18:49 +03002911 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Peller9f259c42011-10-10 10:13:12 +02002912 goto out;
2913
2914 ret = wl1271_ps_elp_wakeup(wl);
2915 if (ret < 0)
2916 goto out;
2917
2918 /* configure each interface */
2919 wl12xx_for_each_wlvif(wl, wlvif) {
2920 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2921 if (ret < 0)
2922 goto out_sleep;
2923 }
2924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925out_sleep:
2926 wl1271_ps_elp_sleep(wl);
2927
2928out:
2929 mutex_unlock(&wl->mutex);
2930
2931 return ret;
2932}
2933
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002934struct wl1271_filter_params {
2935 bool enabled;
2936 int mc_list_length;
2937 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2938};
2939
Jiri Pirko22bedad32010-04-01 21:22:57 +00002940static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2941 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002942{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002943 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002944 struct netdev_hw_addr *ha;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002945
Juuso Oikarinen74441132009-10-13 12:47:53 +03002946 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002947 if (!fp) {
2948 wl1271_error("Out of memory setting filters.");
2949 return 0;
2950 }
2951
2952 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002953 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002954 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2955 fp->enabled = false;
2956 } else {
2957 fp->enabled = true;
2958 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002959 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002960 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002961 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002962 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002963 }
2964
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002965 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002966}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002968#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2969 FIF_ALLMULTI | \
2970 FIF_FCSFAIL | \
2971 FIF_BCN_PRBRESP_PROMISC | \
2972 FIF_CONTROL | \
2973 FIF_OTHER_BSS)
2974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2976 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002977 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002978{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002979 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002981 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002982
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002983 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984
Arik Nemtsov7d057862010-10-16 19:25:35 +02002985 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2986 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002988 mutex_lock(&wl->mutex);
2989
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002990 *total &= WL1271_SUPPORTED_FILTERS;
2991 changed &= WL1271_SUPPORTED_FILTERS;
2992
Ido Yariv4cc53382012-07-24 19:18:49 +03002993 if (unlikely(wl->state != WLCORE_STATE_ON))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002994 goto out;
2995
Ido Yariva6208652011-03-01 15:14:41 +02002996 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002997 if (ret < 0)
2998 goto out;
2999
Eliad Peller6e8cd332011-10-10 10:13:13 +02003000 wl12xx_for_each_wlvif(wl, wlvif) {
3001 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
3002 if (*total & FIF_ALLMULTI)
3003 ret = wl1271_acx_group_address_tbl(wl, wlvif,
3004 false,
3005 NULL, 0);
3006 else if (fp)
3007 ret = wl1271_acx_group_address_tbl(wl, wlvif,
3008 fp->enabled,
3009 fp->mc_list,
3010 fp->mc_list_length);
3011 if (ret < 0)
3012 goto out_sleep;
3013 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02003014 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015
Eliad Peller08c1d1c2011-08-14 13:17:04 +03003016 /*
3017 * the fw doesn't provide an api to configure the filters. instead,
3018 * the filters configuration is based on the active roles / ROC
3019 * state.
3020 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03003021
3022out_sleep:
3023 wl1271_ps_elp_sleep(wl);
3024
3025out:
3026 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02003027 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028}
3029
Eliad Peller170d0e62011-10-05 11:56:06 +02003030static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3031 u8 id, u8 key_type, u8 key_size,
3032 const u8 *key, u8 hlid, u32 tx_seq_32,
3033 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003034{
3035 struct wl1271_ap_key *ap_key;
3036 int i;
3037
3038 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
3039
3040 if (key_size > MAX_KEY_SIZE)
3041 return -EINVAL;
3042
3043 /*
3044 * Find next free entry in ap_keys. Also check we are not replacing
3045 * an existing key.
3046 */
3047 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02003048 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003049 break;
3050
Eliad Peller170d0e62011-10-05 11:56:06 +02003051 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003052 wl1271_warning("trying to record key replacement");
3053 return -EINVAL;
3054 }
3055 }
3056
3057 if (i == MAX_NUM_KEYS)
3058 return -EBUSY;
3059
3060 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
3061 if (!ap_key)
3062 return -ENOMEM;
3063
3064 ap_key->id = id;
3065 ap_key->key_type = key_type;
3066 ap_key->key_size = key_size;
3067 memcpy(ap_key->key, key, key_size);
3068 ap_key->hlid = hlid;
3069 ap_key->tx_seq_32 = tx_seq_32;
3070 ap_key->tx_seq_16 = tx_seq_16;
3071
Eliad Peller170d0e62011-10-05 11:56:06 +02003072 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003073 return 0;
3074}
3075
Eliad Peller170d0e62011-10-05 11:56:06 +02003076static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003077{
3078 int i;
3079
3080 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02003081 kfree(wlvif->ap.recorded_keys[i]);
3082 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003083 }
3084}
3085
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003086static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003087{
3088 int i, ret = 0;
3089 struct wl1271_ap_key *key;
3090 bool wep_key_added = false;
3091
3092 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03003093 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02003094 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003095 break;
3096
Eliad Peller170d0e62011-10-05 11:56:06 +02003097 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03003098 hlid = key->hlid;
3099 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003100 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03003101
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003102 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003103 key->id, key->key_type,
3104 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03003105 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003106 key->tx_seq_16);
3107 if (ret < 0)
3108 goto out;
3109
3110 if (key->key_type == KEY_WEP)
3111 wep_key_added = true;
3112 }
3113
3114 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02003115 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003116 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003117 if (ret < 0)
3118 goto out;
3119 }
3120
3121out:
Eliad Peller170d0e62011-10-05 11:56:06 +02003122 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003123 return ret;
3124}
3125
Eliad Peller536129c2011-10-05 11:55:45 +02003126static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3127 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003128 u8 key_size, const u8 *key, u32 tx_seq_32,
3129 u16 tx_seq_16, struct ieee80211_sta *sta)
3130{
3131 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02003132 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003133
3134 if (is_ap) {
3135 struct wl1271_station *wl_sta;
3136 u8 hlid;
3137
3138 if (sta) {
3139 wl_sta = (struct wl1271_station *)sta->drv_priv;
3140 hlid = wl_sta->hlid;
3141 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003142 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003143 }
3144
Eliad Peller53d40d02011-10-10 10:13:02 +02003145 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003146 /*
3147 * We do not support removing keys after AP shutdown.
3148 * Pretend we do to make mac80211 happy.
3149 */
3150 if (action != KEY_ADD_OR_REPLACE)
3151 return 0;
3152
Eliad Peller170d0e62011-10-05 11:56:06 +02003153 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003154 key_type, key_size,
3155 key, hlid, tx_seq_32,
3156 tx_seq_16);
3157 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003158 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003159 id, key_type, key_size,
3160 key, hlid, tx_seq_32,
3161 tx_seq_16);
3162 }
3163
3164 if (ret < 0)
3165 return ret;
3166 } else {
3167 const u8 *addr;
3168 static const u8 bcast_addr[ETH_ALEN] = {
3169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
3170 };
3171
3172 addr = sta ? sta->addr : bcast_addr;
3173
3174 if (is_zero_ether_addr(addr)) {
3175 /* We dont support TX only encryption */
3176 return -EOPNOTSUPP;
3177 }
3178
3179 /* The wl1271 does not allow to remove unicast keys - they
3180 will be cleared automatically on next CMD_JOIN. Ignore the
3181 request silently, as we dont want the mac80211 to emit
3182 an error message. */
3183 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
3184 return 0;
3185
Eliad Peller010d3d32011-08-14 13:17:31 +03003186 /* don't remove key if hlid was already deleted */
3187 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02003188 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03003189 return 0;
3190
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003191 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003192 id, key_type, key_size,
3193 key, addr, tx_seq_32,
3194 tx_seq_16);
3195 if (ret < 0)
3196 return ret;
3197
3198 /* the default WEP key needs to be configured at least once */
3199 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003200 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02003201 wlvif->default_key,
3202 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003203 if (ret < 0)
3204 return ret;
3205 }
3206 }
3207
3208 return 0;
3209}
3210
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003211static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212 struct ieee80211_vif *vif,
3213 struct ieee80211_sta *sta,
3214 struct ieee80211_key_conf *key_conf)
3215{
3216 struct wl1271 *wl = hw->priv;
Eliad Pelleraf390f42012-09-03 18:27:58 +03003217 int ret;
3218 bool might_change_spare =
3219 key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
3220 key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003221
Eliad Pelleraf390f42012-09-03 18:27:58 +03003222 if (might_change_spare) {
3223 /*
3224 * stop the queues and flush to ensure the next packets are
3225 * in sync with FW spare block accounting
3226 */
Eliad Pelleraf390f42012-09-03 18:27:58 +03003227 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003228 wl1271_tx_flush(wl);
3229 }
3230
3231 mutex_lock(&wl->mutex);
3232
3233 if (unlikely(wl->state != WLCORE_STATE_ON)) {
3234 ret = -EAGAIN;
3235 goto out_wake_queues;
3236 }
3237
3238 ret = wl1271_ps_elp_wakeup(wl);
3239 if (ret < 0)
3240 goto out_wake_queues;
3241
3242 ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
3243
3244 wl1271_ps_elp_sleep(wl);
3245
3246out_wake_queues:
3247 if (might_change_spare)
3248 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
3249
3250 mutex_unlock(&wl->mutex);
3251
3252 return ret;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003253}
3254
3255int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
3256 struct ieee80211_vif *vif,
3257 struct ieee80211_sta *sta,
3258 struct ieee80211_key_conf *key_conf)
3259{
Eliad Peller536129c2011-10-05 11:55:45 +02003260 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003261 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03003262 u32 tx_seq_32 = 0;
3263 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264 u8 key_type;
Arik Nemtsov93d5d102013-03-12 17:19:38 +02003265 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003266
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
3268
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003269 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003270 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02003271 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003272 key_conf->keylen, key_conf->flags);
3273 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
3274
Arik Nemtsov93d5d102013-03-12 17:19:38 +02003275 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
3276 if (sta) {
3277 struct wl1271_station *wl_sta = (void *)sta->drv_priv;
3278 hlid = wl_sta->hlid;
3279 } else {
3280 hlid = wlvif->ap.bcast_hlid;
3281 }
3282 else
3283 hlid = wlvif->sta.hlid;
3284
3285 if (hlid != WL12XX_INVALID_LINK_ID) {
3286 u64 tx_seq = wl->links[hlid].total_freed_pkts;
3287 tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq);
3288 tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq);
3289 }
3290
Johannes Berg97359d12010-08-10 09:46:38 +02003291 switch (key_conf->cipher) {
3292 case WLAN_CIPHER_SUITE_WEP40:
3293 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294 key_type = KEY_WEP;
3295
3296 key_conf->hw_key_idx = key_conf->keyidx;
3297 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003298 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003299 key_type = KEY_TKIP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003300 key_conf->hw_key_idx = key_conf->keyidx;
3301 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003302 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003303 key_type = KEY_AES;
Arik Nemtsov12d4b972011-10-23 08:21:54 +02003304 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003306 case WL1271_CIPHER_SUITE_GEM:
3307 key_type = KEY_GEM;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003308 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003310 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311
Eliad Pelleraf390f42012-09-03 18:27:58 +03003312 return -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003313 }
3314
3315 switch (cmd) {
3316 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003317 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003318 key_conf->keyidx, key_type,
3319 key_conf->keylen, key_conf->key,
3320 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003321 if (ret < 0) {
3322 wl1271_error("Could not add or replace key");
Eliad Pelleraf390f42012-09-03 18:27:58 +03003323 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02003325
3326 /*
3327 * reconfiguring arp response if the unicast (or common)
3328 * encryption key type was changed
3329 */
3330 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
3331 (sta || key_type == KEY_WEP) &&
3332 wlvif->encryption_type != key_type) {
3333 wlvif->encryption_type = key_type;
3334 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3335 if (ret < 0) {
3336 wl1271_warning("build arp rsp failed: %d", ret);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003337 return ret;
Eliad Peller5ec8a442012-02-02 12:22:09 +02003338 }
3339 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340 break;
3341
3342 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003343 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003344 key_conf->keyidx, key_type,
3345 key_conf->keylen, key_conf->key,
3346 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003347 if (ret < 0) {
3348 wl1271_error("Could not remove key");
Eliad Pelleraf390f42012-09-03 18:27:58 +03003349 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003350 }
3351 break;
3352
3353 default:
3354 wl1271_error("Unsupported key cmd 0x%x", cmd);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003355 return -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003356 }
3357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003358 return ret;
3359}
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003360EXPORT_SYMBOL_GPL(wlcore_set_key);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003361
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02003362void wlcore_regdomain_config(struct wl1271 *wl)
3363{
3364 int ret;
3365
3366 if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
3367 return;
3368
3369 mutex_lock(&wl->mutex);
Arik Nemtsov75592be2013-03-12 17:19:45 +02003370
3371 if (unlikely(wl->state != WLCORE_STATE_ON))
3372 goto out;
3373
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02003374 ret = wl1271_ps_elp_wakeup(wl);
3375 if (ret < 0)
3376 goto out;
3377
3378 ret = wlcore_cmd_regdomain_config_locked(wl);
3379 if (ret < 0) {
3380 wl12xx_queue_recovery_work(wl);
3381 goto out;
3382 }
3383
3384 wl1271_ps_elp_sleep(wl);
3385out:
3386 mutex_unlock(&wl->mutex);
3387}
3388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003389static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003390 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003391 struct cfg80211_scan_request *req)
3392{
3393 struct wl1271 *wl = hw->priv;
3394 int ret;
3395 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003396 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003397
3398 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3399
3400 if (req->n_ssids) {
3401 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003402 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003403 }
3404
3405 mutex_lock(&wl->mutex);
3406
Ido Yariv4cc53382012-07-24 19:18:49 +03003407 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003408 /*
3409 * We cannot return -EBUSY here because cfg80211 will expect
3410 * a call to ieee80211_scan_completed if we do - in this case
3411 * there won't be any call.
3412 */
3413 ret = -EAGAIN;
3414 goto out;
3415 }
3416
Ido Yariva6208652011-03-01 15:14:41 +02003417 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003418 if (ret < 0)
3419 goto out;
3420
Eliad Peller97fd3112012-03-04 10:55:52 +02003421 /* fail if there is any role in ROC */
3422 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
Eliad Peller92e712d2011-12-18 20:25:43 +02003423 /* don't allow scanning right now */
3424 ret = -EBUSY;
3425 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003426 }
3427
Eliad Peller78e28062012-11-22 18:06:15 +02003428 ret = wlcore_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003429out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003430 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003431out:
3432 mutex_unlock(&wl->mutex);
3433
3434 return ret;
3435}
3436
Eliad Peller73ecce32011-06-27 13:06:45 +03003437static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3438 struct ieee80211_vif *vif)
3439{
3440 struct wl1271 *wl = hw->priv;
Eliad Peller78e28062012-11-22 18:06:15 +02003441 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller73ecce32011-06-27 13:06:45 +03003442 int ret;
3443
3444 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3445
3446 mutex_lock(&wl->mutex);
3447
Ido Yariv4cc53382012-07-24 19:18:49 +03003448 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Peller73ecce32011-06-27 13:06:45 +03003449 goto out;
3450
3451 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3452 goto out;
3453
3454 ret = wl1271_ps_elp_wakeup(wl);
3455 if (ret < 0)
3456 goto out;
3457
3458 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
Eliad Peller78e28062012-11-22 18:06:15 +02003459 ret = wl->ops->scan_stop(wl, wlvif);
Eliad Peller73ecce32011-06-27 13:06:45 +03003460 if (ret < 0)
3461 goto out_sleep;
3462 }
Arik Nemtsov55df5af2012-03-03 22:18:00 +02003463
3464 /*
3465 * Rearm the tx watchdog just before idling scan. This
3466 * prevents just-finished scans from triggering the watchdog
3467 */
3468 wl12xx_rearm_tx_watchdog_locked(wl);
3469
Eliad Peller73ecce32011-06-27 13:06:45 +03003470 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3471 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Pellerc50a2822012-11-22 18:06:19 +02003472 wl->scan_wlvif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003473 wl->scan.req = NULL;
3474 ieee80211_scan_completed(wl->hw, true);
3475
3476out_sleep:
3477 wl1271_ps_elp_sleep(wl);
3478out:
3479 mutex_unlock(&wl->mutex);
3480
3481 cancel_delayed_work_sync(&wl->scan_complete_work);
3482}
3483
Luciano Coelho33c2c062011-05-10 14:46:02 +03003484static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3485 struct ieee80211_vif *vif,
3486 struct cfg80211_sched_scan_request *req,
3487 struct ieee80211_sched_scan_ies *ies)
3488{
3489 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003490 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003491 int ret;
3492
3493 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3494
3495 mutex_lock(&wl->mutex);
3496
Ido Yariv4cc53382012-07-24 19:18:49 +03003497 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003498 ret = -EAGAIN;
3499 goto out;
3500 }
3501
Luciano Coelho33c2c062011-05-10 14:46:02 +03003502 ret = wl1271_ps_elp_wakeup(wl);
3503 if (ret < 0)
3504 goto out;
3505
Eliad Peller78e28062012-11-22 18:06:15 +02003506 ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003507 if (ret < 0)
3508 goto out_sleep;
3509
Eliad Peller10199752012-11-22 18:06:23 +02003510 wl->sched_vif = wlvif;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003511
3512out_sleep:
3513 wl1271_ps_elp_sleep(wl);
3514out:
3515 mutex_unlock(&wl->mutex);
3516 return ret;
3517}
3518
3519static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3520 struct ieee80211_vif *vif)
3521{
3522 struct wl1271 *wl = hw->priv;
Yoni Divinsky78f85f52012-05-16 11:34:17 +03003523 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003524 int ret;
3525
3526 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3527
3528 mutex_lock(&wl->mutex);
3529
Ido Yariv4cc53382012-07-24 19:18:49 +03003530 if (unlikely(wl->state != WLCORE_STATE_ON))
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003531 goto out;
3532
Luciano Coelho33c2c062011-05-10 14:46:02 +03003533 ret = wl1271_ps_elp_wakeup(wl);
3534 if (ret < 0)
3535 goto out;
3536
Eliad Peller78e28062012-11-22 18:06:15 +02003537 wl->ops->sched_scan_stop(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003538
3539 wl1271_ps_elp_sleep(wl);
3540out:
3541 mutex_unlock(&wl->mutex);
3542}
3543
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003544static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3545{
3546 struct wl1271 *wl = hw->priv;
3547 int ret = 0;
3548
3549 mutex_lock(&wl->mutex);
3550
Ido Yariv4cc53382012-07-24 19:18:49 +03003551 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003552 ret = -EAGAIN;
3553 goto out;
3554 }
3555
Ido Yariva6208652011-03-01 15:14:41 +02003556 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003557 if (ret < 0)
3558 goto out;
3559
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003560 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003561 if (ret < 0)
3562 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3563
3564 wl1271_ps_elp_sleep(wl);
3565
3566out:
3567 mutex_unlock(&wl->mutex);
3568
3569 return ret;
3570}
3571
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003572static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3573{
3574 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003575 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003576 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003577
3578 mutex_lock(&wl->mutex);
3579
Ido Yariv4cc53382012-07-24 19:18:49 +03003580 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003581 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003582 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003583 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003584
Ido Yariva6208652011-03-01 15:14:41 +02003585 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003586 if (ret < 0)
3587 goto out;
3588
Eliad Peller6e8cd332011-10-10 10:13:13 +02003589 wl12xx_for_each_wlvif(wl, wlvif) {
3590 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3591 if (ret < 0)
3592 wl1271_warning("set rts threshold failed: %d", ret);
3593 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003594 wl1271_ps_elp_sleep(wl);
3595
3596out:
3597 mutex_unlock(&wl->mutex);
3598
3599 return ret;
3600}
3601
Eliad Pellerd48055d2011-09-15 12:07:04 +03003602static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3603{
3604 int len;
3605 const u8 *next, *end = skb->data + skb->len;
3606 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3607 skb->len - ieoffset);
3608 if (!ie)
3609 return;
3610 len = ie[1] + 2;
3611 next = ie + len;
3612 memmove(ie, next, end - next);
3613 skb_trim(skb, skb->len - len);
3614}
3615
Eliad Peller26b4bf22011-09-15 12:07:05 +03003616static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3617 unsigned int oui, u8 oui_type,
3618 int ieoffset)
3619{
3620 int len;
3621 const u8 *next, *end = skb->data + skb->len;
3622 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3623 skb->data + ieoffset,
3624 skb->len - ieoffset);
3625 if (!ie)
3626 return;
3627 len = ie[1] + 2;
3628 next = ie + len;
3629 memmove(ie, next, end - next);
3630 skb_trim(skb, skb->len - len);
3631}
3632
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003633static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3634 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003635{
Eliad Pellercdaac622012-01-31 11:57:16 +02003636 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003637 struct sk_buff *skb;
3638 int ret;
3639
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003640 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003641 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003642 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003643
Eliad Pellercdaac622012-01-31 11:57:16 +02003644 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003645 CMD_TEMPL_AP_PROBE_RESPONSE,
3646 skb->data,
3647 skb->len, 0,
3648 rates);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003649 dev_kfree_skb(skb);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003650
3651 if (ret < 0)
3652 goto out;
3653
3654 wl1271_debug(DEBUG_AP, "probe response updated");
3655 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3656
3657out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003658 return ret;
3659}
3660
3661static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3662 struct ieee80211_vif *vif,
3663 u8 *probe_rsp_data,
3664 size_t probe_rsp_len,
3665 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003666{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003667 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3668 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003669 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3670 int ssid_ie_offset, ie_offset, templ_len;
3671 const u8 *ptr;
3672
3673 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003674 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003675 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003676 CMD_TEMPL_AP_PROBE_RESPONSE,
3677 probe_rsp_data,
3678 probe_rsp_len, 0,
3679 rates);
3680
3681 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3682 wl1271_error("probe_rsp template too big");
3683 return -EINVAL;
3684 }
3685
3686 /* start searching from IE offset */
3687 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3688
3689 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3690 probe_rsp_len - ie_offset);
3691 if (!ptr) {
3692 wl1271_error("No SSID in beacon!");
3693 return -EINVAL;
3694 }
3695
3696 ssid_ie_offset = ptr - probe_rsp_data;
3697 ptr += (ptr[1] + 2);
3698
3699 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3700
3701 /* insert SSID from bss_conf */
3702 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3703 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3704 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3705 bss_conf->ssid, bss_conf->ssid_len);
3706 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3707
3708 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3709 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3710 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3711
Eliad Pellercdaac622012-01-31 11:57:16 +02003712 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003713 CMD_TEMPL_AP_PROBE_RESPONSE,
3714 probe_rsp_templ,
3715 templ_len, 0,
3716 rates);
3717}
3718
Arik Nemtsove78a2872010-10-16 19:07:21 +02003719static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003720 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003721 struct ieee80211_bss_conf *bss_conf,
3722 u32 changed)
3723{
Eliad Peller0603d892011-10-05 11:55:51 +02003724 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003725 int ret = 0;
3726
3727 if (changed & BSS_CHANGED_ERP_SLOT) {
3728 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003729 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003730 else
Eliad Peller0603d892011-10-05 11:55:51 +02003731 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003732 if (ret < 0) {
3733 wl1271_warning("Set slot time failed %d", ret);
3734 goto out;
3735 }
3736 }
3737
3738 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3739 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003740 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003741 else
Eliad Peller0603d892011-10-05 11:55:51 +02003742 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003743 }
3744
3745 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3746 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003747 ret = wl1271_acx_cts_protect(wl, wlvif,
3748 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003749 else
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_acx_cts_protect(wl, wlvif,
3751 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003752 if (ret < 0) {
3753 wl1271_warning("Set ctsprotect failed %d", ret);
3754 goto out;
3755 }
3756 }
3757
3758out:
3759 return ret;
3760}
3761
Luciano Coelho62c2e572012-05-10 12:14:04 +03003762static int wlcore_set_beacon_template(struct wl1271 *wl,
3763 struct ieee80211_vif *vif,
3764 bool is_ap)
3765{
3766 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3767 struct ieee80211_hdr *hdr;
3768 u32 min_rate;
3769 int ret;
Luciano Coelho8f6ac532013-05-04 01:06:11 +03003770 int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003771 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3772 u16 tmpl_id;
3773
3774 if (!beacon) {
3775 ret = -EINVAL;
3776 goto out;
3777 }
3778
3779 wl1271_debug(DEBUG_MASTER, "beacon updated");
3780
Eliad Peller3230f352012-11-20 13:20:01 +02003781 ret = wl1271_ssid_set(wlvif, beacon, ieoffset);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003782 if (ret < 0) {
3783 dev_kfree_skb(beacon);
3784 goto out;
3785 }
3786 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
3787 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3788 CMD_TEMPL_BEACON;
3789 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
3790 beacon->data,
3791 beacon->len, 0,
3792 min_rate);
3793 if (ret < 0) {
3794 dev_kfree_skb(beacon);
3795 goto out;
3796 }
3797
Eliad Pellerd50529c2012-11-22 18:06:20 +02003798 wlvif->wmm_enabled =
3799 cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
3800 WLAN_OUI_TYPE_MICROSOFT_WMM,
3801 beacon->data + ieoffset,
3802 beacon->len - ieoffset);
3803
Luciano Coelho62c2e572012-05-10 12:14:04 +03003804 /*
3805 * In case we already have a probe-resp beacon set explicitly
3806 * by usermode, don't use the beacon data.
3807 */
3808 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3809 goto end_bcn;
3810
3811 /* remove TIM ie from probe response */
3812 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3813
3814 /*
3815 * remove p2p ie from probe response.
3816 * the fw reponds to probe requests that don't include
3817 * the p2p ie. probe requests with p2p ie will be passed,
3818 * and will be responded by the supplicant (the spec
3819 * forbids including the p2p ie when responding to probe
3820 * requests that didn't include it).
3821 */
3822 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3823 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3824
3825 hdr = (struct ieee80211_hdr *) beacon->data;
3826 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3827 IEEE80211_STYPE_PROBE_RESP);
3828 if (is_ap)
3829 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
3830 beacon->data,
3831 beacon->len,
3832 min_rate);
3833 else
3834 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
3835 CMD_TEMPL_PROBE_RESPONSE,
3836 beacon->data,
3837 beacon->len, 0,
3838 min_rate);
3839end_bcn:
3840 dev_kfree_skb(beacon);
3841 if (ret < 0)
3842 goto out;
3843
3844out:
3845 return ret;
3846}
3847
Arik Nemtsove78a2872010-10-16 19:07:21 +02003848static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3849 struct ieee80211_vif *vif,
3850 struct ieee80211_bss_conf *bss_conf,
3851 u32 changed)
3852{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003853 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003854 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003855 int ret = 0;
3856
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003857 if (changed & BSS_CHANGED_BEACON_INT) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003858 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3859 bss_conf->beacon_int);
3860
Eliad Peller6a899792011-10-05 11:55:58 +02003861 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003862 }
3863
Arik Nemtsov560f002412011-11-08 18:46:54 +02003864 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3865 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003866
3867 wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003868 }
3869
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003870 if (changed & BSS_CHANGED_BEACON) {
Luciano Coelho62c2e572012-05-10 12:14:04 +03003871 ret = wlcore_set_beacon_template(wl, vif, is_ap);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003872 if (ret < 0)
3873 goto out;
3874 }
3875
3876out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003877 if (ret != 0)
3878 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003879 return ret;
3880}
3881
3882/* AP mode changes */
3883static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003884 struct ieee80211_vif *vif,
3885 struct ieee80211_bss_conf *bss_conf,
3886 u32 changed)
3887{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003888 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003889 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003890
Eliad Pellerb6970ee2012-11-20 13:20:05 +02003891 if (changed & BSS_CHANGED_BASIC_RATES) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003892 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003893
Eliad Peller87fbcb02011-10-05 11:55:41 +02003894 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003895 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003896 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003897 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003898
Eliad Peller87fbcb02011-10-05 11:55:41 +02003899 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003900 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003901 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003902 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003903 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003904
Eliad Peller784f6942011-10-05 11:55:39 +02003905 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003906 if (ret < 0)
3907 goto out;
Luciano Coelho62c2e572012-05-10 12:14:04 +03003908
3909 ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
3910 if (ret < 0)
3911 goto out;
3912
3913 ret = wlcore_set_beacon_template(wl, vif, true);
3914 if (ret < 0)
3915 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003916 }
3917
Arik Nemtsove78a2872010-10-16 19:07:21 +02003918 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3919 if (ret < 0)
3920 goto out;
3921
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003922 if (changed & BSS_CHANGED_BEACON_ENABLED) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003923 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003924 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003925 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003926 if (ret < 0)
3927 goto out;
3928
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003929 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003930 if (ret < 0)
3931 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003932
Eliad Peller53d40d02011-10-10 10:13:02 +02003933 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003934 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003935 }
3936 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003937 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003938 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003939 if (ret < 0)
3940 goto out;
3941
Eliad Peller53d40d02011-10-10 10:13:02 +02003942 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003943 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3944 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003945 wl1271_debug(DEBUG_AP, "stopped AP");
3946 }
3947 }
3948 }
3949
Eliad Peller0603d892011-10-05 11:55:51 +02003950 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003951 if (ret < 0)
3952 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003953
3954 /* Handle HT information change */
3955 if ((changed & BSS_CHANGED_HT) &&
Johannes Berg4bf88532012-11-09 11:39:59 +01003956 (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003957 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003958 bss_conf->ht_operation_mode);
3959 if (ret < 0) {
3960 wl1271_warning("Set ht information failed %d", ret);
3961 goto out;
3962 }
3963 }
3964
Arik Nemtsove78a2872010-10-16 19:07:21 +02003965out:
3966 return;
3967}
3968
Eliad Peller3230f352012-11-20 13:20:01 +02003969static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3970 struct ieee80211_bss_conf *bss_conf,
3971 u32 sta_rate_set)
3972{
3973 u32 rates;
3974 int ret;
3975
3976 wl1271_debug(DEBUG_MAC80211,
3977 "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x",
3978 bss_conf->bssid, bss_conf->aid,
3979 bss_conf->beacon_int,
3980 bss_conf->basic_rates, sta_rate_set);
3981
3982 wlvif->beacon_int = bss_conf->beacon_int;
3983 rates = bss_conf->basic_rates;
3984 wlvif->basic_rate_set =
3985 wl1271_tx_enabled_rates_get(wl, rates,
3986 wlvif->band);
3987 wlvif->basic_rate =
3988 wl1271_tx_min_rate_get(wl,
3989 wlvif->basic_rate_set);
3990
3991 if (sta_rate_set)
3992 wlvif->rate_set =
3993 wl1271_tx_enabled_rates_get(wl,
3994 sta_rate_set,
3995 wlvif->band);
3996
3997 /* we only support sched_scan while not connected */
Eliad Peller10199752012-11-22 18:06:23 +02003998 if (wl->sched_vif == wlvif)
Eliad Peller78e28062012-11-22 18:06:15 +02003999 wl->ops->sched_scan_stop(wl, wlvif);
Eliad Peller3230f352012-11-20 13:20:01 +02004000
4001 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4002 if (ret < 0)
4003 return ret;
4004
4005 ret = wl12xx_cmd_build_null_data(wl, wlvif);
4006 if (ret < 0)
4007 return ret;
4008
4009 ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif));
4010 if (ret < 0)
4011 return ret;
4012
4013 wlcore_set_ssid(wl, wlvif);
4014
4015 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
4016
4017 return 0;
4018}
4019
4020static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4021{
4022 int ret;
4023
4024 /* revert back to minimum rates for the current band */
4025 wl1271_set_band_rate(wl, wlvif);
4026 wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4027
4028 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4029 if (ret < 0)
4030 return ret;
4031
4032 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4033 test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) {
4034 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
4035 if (ret < 0)
4036 return ret;
4037 }
4038
4039 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
4040 return 0;
4041}
Arik Nemtsove78a2872010-10-16 19:07:21 +02004042/* STA/IBSS mode changes */
4043static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
4044 struct ieee80211_vif *vif,
4045 struct ieee80211_bss_conf *bss_conf,
4046 u32 changed)
4047{
Eliad Peller87fbcb02011-10-05 11:55:41 +02004048 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller3230f352012-11-20 13:20:01 +02004049 bool do_join = false;
Eliad Peller536129c2011-10-05 11:55:45 +02004050 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03004051 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004052 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02004053 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01004054 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02004055 bool sta_exists = false;
4056 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02004057
4058 if (is_ibss) {
4059 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
4060 changed);
4061 if (ret < 0)
4062 goto out;
4063 }
4064
Eliad Peller227e81e2011-08-14 13:17:26 +03004065 if (changed & BSS_CHANGED_IBSS) {
4066 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02004067 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03004068 ibss_joined = true;
4069 } else {
Eliad Peller3230f352012-11-20 13:20:01 +02004070 wlcore_unset_assoc(wl, wlvif);
4071 wl12xx_cmd_role_stop_sta(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03004072 }
4073 }
4074
4075 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004076 do_join = true;
4077
4078 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03004079 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004080 do_join = true;
4081
Eliad Peller227e81e2011-08-14 13:17:26 +03004082 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02004083 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
4084 bss_conf->enable_beacon ? "enabled" : "disabled");
4085
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02004086 do_join = true;
4087 }
4088
Luciano Coelho48af2eb2012-11-20 11:03:32 +02004089 if (changed & BSS_CHANGED_CQM) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004090 bool enable = false;
4091 if (bss_conf->cqm_rssi_thold)
4092 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02004093 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004094 bss_conf->cqm_rssi_thold,
4095 bss_conf->cqm_rssi_hyst);
4096 if (ret < 0)
4097 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02004098 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004099 }
4100
Eliad Pellerec870112012-11-20 13:20:09 +02004101 if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT |
4102 BSS_CHANGED_ASSOC)) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004103 rcu_read_lock();
4104 sta = ieee80211_find_sta(vif, bss_conf->bssid);
Luciano Coelhoef08d022012-11-20 11:03:31 +02004105 if (sta) {
4106 u8 *rx_mask = sta->ht_cap.mcs.rx_mask;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004107
Luciano Coelhoef08d022012-11-20 11:03:31 +02004108 /* save the supp_rates of the ap */
4109 sta_rate_set = sta->supp_rates[wlvif->band];
4110 if (sta->ht_cap.ht_supported)
4111 sta_rate_set |=
4112 (rx_mask[0] << HW_HT_RATES_OFFSET) |
4113 (rx_mask[1] << HW_MIMO_RATES_OFFSET);
4114 sta_ht_cap = sta->ht_cap;
4115 sta_exists = true;
4116 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004117
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004118 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004119 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004120
Eliad Peller3230f352012-11-20 13:20:01 +02004121 if (changed & BSS_CHANGED_BSSID) {
4122 if (!is_zero_ether_addr(bss_conf->bssid)) {
4123 ret = wlcore_set_bssid(wl, wlvif, bss_conf,
4124 sta_rate_set);
4125 if (ret < 0)
4126 goto out;
4127
4128 /* Need to update the BSSID (for filtering etc) */
Eliad Peller446f5ca2012-03-12 14:53:04 +02004129 do_join = true;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03004130 } else {
Eliad Peller3230f352012-11-20 13:20:01 +02004131 ret = wlcore_clear_bssid(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004132 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004133 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004134 }
4135 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004136
Eliad Pellerd192d262011-05-24 14:33:08 +03004137 if (changed & BSS_CHANGED_IBSS) {
4138 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
4139 bss_conf->ibss_joined);
4140
4141 if (bss_conf->ibss_joined) {
4142 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02004143 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004144 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02004145 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02004146 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02004147 wl1271_tx_min_rate_get(wl,
4148 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03004149
Shahar Levi06b660e2011-09-05 13:54:36 +03004150 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02004151 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
4152 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03004153 if (ret < 0)
4154 goto out;
4155 }
4156 }
4157
Eliad Peller0603d892011-10-05 11:55:51 +02004158 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004159 if (ret < 0)
4160 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004161
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004162 if (do_join) {
Eliad Peller3230f352012-11-20 13:20:01 +02004163 ret = wlcore_join(wl, wlvif);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004164 if (ret < 0) {
4165 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004166 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004167 }
Eliad Peller3230f352012-11-20 13:20:01 +02004168 }
Eliad Peller251c1772011-08-14 13:17:17 +03004169
Eliad Peller3230f352012-11-20 13:20:01 +02004170 if (changed & BSS_CHANGED_ASSOC) {
4171 if (bss_conf->assoc) {
Eliad Pellerec870112012-11-20 13:20:09 +02004172 ret = wlcore_set_assoc(wl, wlvif, bss_conf,
4173 sta_rate_set);
Eliad Peller251c1772011-08-14 13:17:17 +03004174 if (ret < 0)
4175 goto out;
4176
Eliad Peller9fd6f212012-03-04 10:55:48 +02004177 if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
4178 wl12xx_set_authorized(wl, wlvif);
Eliad Peller3230f352012-11-20 13:20:01 +02004179 } else {
4180 wlcore_unset_assoc(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03004181 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02004182 }
4183
Eliad Peller518b6802012-11-26 18:05:47 +02004184 if (changed & BSS_CHANGED_PS) {
4185 if ((bss_conf->ps) &&
4186 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
4187 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
4188 int ps_mode;
4189 char *ps_mode_str;
4190
4191 if (wl->conf.conn.forced_ps) {
4192 ps_mode = STATION_POWER_SAVE_MODE;
4193 ps_mode_str = "forced";
4194 } else {
4195 ps_mode = STATION_AUTO_PS_MODE;
4196 ps_mode_str = "auto";
4197 }
4198
4199 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
4200
4201 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
Kalle Valoc6999d82010-02-18 13:25:41 +02004202 if (ret < 0)
Eliad Peller518b6802012-11-26 18:05:47 +02004203 wl1271_warning("enter %s ps failed %d",
4204 ps_mode_str, ret);
4205 } else if (!bss_conf->ps &&
4206 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
4207 wl1271_debug(DEBUG_PSM, "auto ps disabled");
4208
4209 ret = wl1271_ps_set_mode(wl, wlvif,
4210 STATION_ACTIVE_MODE);
4211 if (ret < 0)
4212 wl1271_warning("exit auto ps failed %d", ret);
Kalle Valoc6999d82010-02-18 13:25:41 +02004213 }
4214 }
Kalle Valo4695dc92010-03-18 12:26:38 +02004215
4216 /* Handle new association with HT. Do this after join. */
Eliad Peller58321b22012-11-20 13:20:10 +02004217 if (sta_exists &&
4218 (changed & BSS_CHANGED_HT)) {
4219 bool enabled =
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004220 bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004221
Eliad Peller530abe12012-11-28 11:42:31 +02004222 ret = wlcore_hw_set_peer_cap(wl,
4223 &sta_ht_cap,
4224 enabled,
4225 wlvif->rate_set,
4226 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004227 if (ret < 0) {
Eliad Peller58321b22012-11-20 13:20:10 +02004228 wl1271_warning("Set ht cap failed %d", ret);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004229 goto out;
Eliad Peller58321b22012-11-20 13:20:10 +02004230
4231 }
4232
4233 if (enabled) {
4234 ret = wl1271_acx_set_ht_information(wl, wlvif,
4235 bss_conf->ht_operation_mode);
4236 if (ret < 0) {
4237 wl1271_warning("Set ht information failed %d",
4238 ret);
4239 goto out;
4240 }
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004241 }
4242 }
4243
Eliad Peller76a74c82012-02-02 12:22:11 +02004244 /* Handle arp filtering. Done after join. */
4245 if ((changed & BSS_CHANGED_ARP_FILTER) ||
4246 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
4247 __be32 addr = bss_conf->arp_addr_list[0];
4248 wlvif->sta.qos = bss_conf->qos;
4249 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
4250
Johannes Berg0f19b412013-01-14 16:39:07 +01004251 if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
Eliad Peller76a74c82012-02-02 12:22:11 +02004252 wlvif->ip_addr = addr;
4253 /*
4254 * The template should have been configured only upon
4255 * association. however, it seems that the correct ip
4256 * isn't being set (when sending), so we have to
4257 * reconfigure the template upon every ip change.
4258 */
4259 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
4260 if (ret < 0) {
4261 wl1271_warning("build arp rsp failed: %d", ret);
4262 goto out;
4263 }
4264
4265 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
4266 (ACX_ARP_FILTER_ARP_FILTERING |
4267 ACX_ARP_FILTER_AUTO_ARP),
4268 addr);
4269 } else {
4270 wlvif->ip_addr = 0;
4271 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
4272 }
4273
4274 if (ret < 0)
4275 goto out;
4276 }
4277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004278out:
4279 return;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004280}
4281
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004282static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
4283 struct ieee80211_vif *vif,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004284 struct ieee80211_bss_conf *bss_conf,
4285 u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004286{
4287 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004288 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4289 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004290 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004291
Eliad Pellerd3f5a1b2012-11-19 17:14:05 +02004292 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x",
4293 wlvif->role_id, (int)changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004294
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03004295 /*
4296 * make sure to cancel pending disconnections if our association
4297 * state changed
4298 */
4299 if (!is_ap && (changed & BSS_CHANGED_ASSOC))
Eliad Pellerc50a2822012-11-22 18:06:19 +02004300 cancel_delayed_work_sync(&wlvif->connection_loss_work);
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03004301
Eliad Pellerb515d832012-05-15 17:08:56 +03004302 if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
4303 !bss_conf->enable_beacon)
4304 wl1271_tx_flush(wl);
4305
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004306 mutex_lock(&wl->mutex);
4307
Ido Yariv4cc53382012-07-24 19:18:49 +03004308 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004309 goto out;
4310
Eliad Peller10c8cd02011-10-10 10:13:06 +02004311 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
4312 goto out;
4313
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004314 ret = wl1271_ps_elp_wakeup(wl);
4315 if (ret < 0)
4316 goto out;
4317
4318 if (is_ap)
4319 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
4320 else
4321 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
4322
4323 wl1271_ps_elp_sleep(wl);
4324
4325out:
4326 mutex_unlock(&wl->mutex);
4327}
4328
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004329static int wlcore_op_add_chanctx(struct ieee80211_hw *hw,
4330 struct ieee80211_chanctx_conf *ctx)
4331{
4332 wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004333 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4334 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004335 return 0;
4336}
4337
4338static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw,
4339 struct ieee80211_chanctx_conf *ctx)
4340{
4341 wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004342 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4343 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004344}
4345
4346static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
4347 struct ieee80211_chanctx_conf *ctx,
4348 u32 changed)
4349{
4350 wl1271_debug(DEBUG_MAC80211,
4351 "mac80211 change chanctx %d (type %d) changed 0x%x",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004352 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4353 cfg80211_get_chandef_type(&ctx->def), changed);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004354}
4355
4356static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
4357 struct ieee80211_vif *vif,
4358 struct ieee80211_chanctx_conf *ctx)
4359{
4360 struct wl1271 *wl = hw->priv;
4361 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4362 int channel = ieee80211_frequency_to_channel(
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004363 ctx->def.chan->center_freq);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004364
4365 wl1271_debug(DEBUG_MAC80211,
4366 "mac80211 assign chanctx (role %d) %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004367 wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004368
4369 mutex_lock(&wl->mutex);
4370
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004371 wlvif->band = ctx->def.chan->band;
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004372 wlvif->channel = channel;
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004373 wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004374
4375 /* update default rates according to the band */
4376 wl1271_set_band_rate(wl, wlvif);
4377
4378 mutex_unlock(&wl->mutex);
4379
4380 return 0;
4381}
4382
4383static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
4384 struct ieee80211_vif *vif,
4385 struct ieee80211_chanctx_conf *ctx)
4386{
4387 struct wl1271 *wl = hw->priv;
4388 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4389
4390 wl1271_debug(DEBUG_MAC80211,
4391 "mac80211 unassign chanctx (role %d) %d (type %d)",
4392 wlvif->role_id,
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004393 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4394 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004395
4396 wl1271_tx_flush(wl);
4397}
4398
Eliad Peller8a3a3c82011-10-02 10:15:52 +02004399static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
4400 struct ieee80211_vif *vif, u16 queue,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004401 const struct ieee80211_tx_queue_params *params)
4402{
4403 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004404 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405 u8 ps_scheme;
4406 int ret = 0;
4407
4408 mutex_lock(&wl->mutex);
4409
4410 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4411
4412 if (params->uapsd)
4413 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4414 else
4415 ps_scheme = CONF_PS_SCHEME_LEGACY;
4416
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004417 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004418 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004419
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004420 ret = wl1271_ps_elp_wakeup(wl);
4421 if (ret < 0)
4422 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004423
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004424 /*
4425 * the txop is confed in units of 32us by the mac80211,
4426 * we need us
4427 */
Eliad Peller0603d892011-10-05 11:55:51 +02004428 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004429 params->cw_min, params->cw_max,
4430 params->aifs, params->txop << 5);
4431 if (ret < 0)
4432 goto out_sleep;
4433
Eliad Peller0603d892011-10-05 11:55:51 +02004434 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004435 CONF_CHANNEL_TYPE_EDCF,
4436 wl1271_tx_get_queue(queue),
4437 ps_scheme, CONF_ACK_POLICY_LEGACY,
4438 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004439
4440out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004441 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004442
4443out:
4444 mutex_unlock(&wl->mutex);
4445
4446 return ret;
4447}
4448
Eliad Peller37a41b42011-09-21 14:06:11 +03004449static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4450 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451{
4452
4453 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004454 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 u64 mactime = ULLONG_MAX;
4456 int ret;
4457
4458 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4459
4460 mutex_lock(&wl->mutex);
4461
Ido Yariv4cc53382012-07-24 19:18:49 +03004462 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004463 goto out;
4464
Ido Yariva6208652011-03-01 15:14:41 +02004465 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466 if (ret < 0)
4467 goto out;
4468
Eliad Peller9c531142012-01-31 11:57:18 +02004469 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 if (ret < 0)
4471 goto out_sleep;
4472
4473out_sleep:
4474 wl1271_ps_elp_sleep(wl);
4475
4476out:
4477 mutex_unlock(&wl->mutex);
4478 return mactime;
4479}
4480
4481static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4482 struct survey_info *survey)
4483{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004484 struct ieee80211_conf *conf = &hw->conf;
4485
4486 if (idx != 0)
4487 return -ENOENT;
4488
Karl Beldan675a0b02013-03-25 16:26:57 +01004489 survey->channel = conf->chandef.chan;
Yoni Divinskyadd779a02012-06-13 18:56:54 +03004490 survey->filled = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004491 return 0;
4492}
4493
Arik Nemtsov409622e2011-02-23 00:22:29 +02004494static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004495 struct wl12xx_vif *wlvif,
4496 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004497{
4498 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004499 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004500
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004501
4502 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004503 wl1271_warning("could not allocate HLID - too much stations");
4504 return -EBUSY;
4505 }
4506
4507 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004508 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4509 if (ret < 0) {
4510 wl1271_warning("could not allocate HLID - too many links");
4511 return -EBUSY;
4512 }
4513
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004514 /* use the previous security seq, if this is a recovery/resume */
4515 wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts;
4516
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004517 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004518 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004519 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004520 return 0;
4521}
4522
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004523void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004524{
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004525 struct wl1271_station *wl_sta;
4526 struct ieee80211_sta *sta;
4527 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4528
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004529 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004530 return;
4531
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004532 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004533 __clear_bit(hlid, &wl->ap_ps_map);
4534 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004535
4536 /*
4537 * save the last used PN in the private part of iee80211_sta,
4538 * in case of recovery/suspend
4539 */
4540 rcu_read_lock();
4541 sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
4542 if (sta) {
4543 wl_sta = (void *)sta->drv_priv;
4544 wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
4545
4546 /*
4547 * increment the initial seq number on recovery to account for
4548 * transmitted packets that we haven't yet got in the FW status
4549 */
4550 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
4551 wl_sta->total_freed_pkts +=
4552 WL1271_TX_SQN_POST_RECOVERY_PADDING;
4553 }
4554 rcu_read_unlock();
4555
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004556 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004557 wl->active_sta_count--;
Arik Nemtsov55df5af2012-03-03 22:18:00 +02004558
4559 /*
4560 * rearm the tx watchdog when the last STA is freed - give the FW a
4561 * chance to return STA-buffered packets before complaining.
4562 */
4563 if (wl->active_sta_count == 0)
4564 wl12xx_rearm_tx_watchdog_locked(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004565}
4566
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004567static int wl12xx_sta_add(struct wl1271 *wl,
4568 struct wl12xx_vif *wlvif,
4569 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004570{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004571 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004572 int ret = 0;
4573 u8 hlid;
4574
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004575 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4576
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004577 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004578 if (ret < 0)
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004579 return ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004580
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004581 wl_sta = (struct wl1271_station *)sta->drv_priv;
4582 hlid = wl_sta->hlid;
4583
Eliad Peller1b92f152011-10-10 10:13:09 +02004584 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004585 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004586 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004587
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004588 return ret;
4589}
4590
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004591static int wl12xx_sta_remove(struct wl1271 *wl,
4592 struct wl12xx_vif *wlvif,
4593 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004594{
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004595 struct wl1271_station *wl_sta;
4596 int ret = 0, id;
4597
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004598 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4599
4600 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004601 id = wl_sta->hlid;
4602 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004603 return -EINVAL;
4604
4605 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
4606 if (ret < 0)
4607 return ret;
4608
4609 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
4610 return ret;
4611}
4612
Eliad Peller426001a2012-11-26 18:05:45 +02004613static void wlcore_roc_if_possible(struct wl1271 *wl,
4614 struct wl12xx_vif *wlvif)
4615{
4616 if (find_first_bit(wl->roc_map,
4617 WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)
4618 return;
4619
4620 if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID))
4621 return;
4622
4623 wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
4624}
4625
4626static void wlcore_update_inconn_sta(struct wl1271 *wl,
4627 struct wl12xx_vif *wlvif,
4628 struct wl1271_station *wl_sta,
4629 bool in_connection)
4630{
4631 if (in_connection) {
4632 if (WARN_ON(wl_sta->in_connection))
4633 return;
4634 wl_sta->in_connection = true;
4635 if (!wlvif->inconn_count++)
4636 wlcore_roc_if_possible(wl, wlvif);
4637 } else {
4638 if (!wl_sta->in_connection)
4639 return;
4640
4641 wl_sta->in_connection = false;
4642 wlvif->inconn_count--;
4643 if (WARN_ON(wlvif->inconn_count < 0))
4644 return;
4645
4646 if (!wlvif->inconn_count)
4647 if (test_bit(wlvif->role_id, wl->roc_map))
4648 wl12xx_croc(wl, wlvif->role_id);
4649 }
4650}
4651
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004652static int wl12xx_update_sta_state(struct wl1271 *wl,
4653 struct wl12xx_vif *wlvif,
4654 struct ieee80211_sta *sta,
4655 enum ieee80211_sta_state old_state,
4656 enum ieee80211_sta_state new_state)
4657{
4658 struct wl1271_station *wl_sta;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004659 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
4660 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
4661 int ret;
4662
4663 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004664
4665 /* Add station (AP mode) */
4666 if (is_ap &&
4667 old_state == IEEE80211_STA_NOTEXIST &&
Eliad Peller29936262012-11-20 13:20:06 +02004668 new_state == IEEE80211_STA_NONE) {
4669 ret = wl12xx_sta_add(wl, wlvif, sta);
4670 if (ret)
4671 return ret;
Eliad Peller426001a2012-11-26 18:05:45 +02004672
4673 wlcore_update_inconn_sta(wl, wlvif, wl_sta, true);
Eliad Peller29936262012-11-20 13:20:06 +02004674 }
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004675
4676 /* Remove station (AP mode) */
4677 if (is_ap &&
4678 old_state == IEEE80211_STA_NONE &&
4679 new_state == IEEE80211_STA_NOTEXIST) {
4680 /* must not fail */
4681 wl12xx_sta_remove(wl, wlvif, sta);
Eliad Peller426001a2012-11-26 18:05:45 +02004682
4683 wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004684 }
4685
4686 /* Authorize station (AP mode) */
4687 if (is_ap &&
4688 new_state == IEEE80211_STA_AUTHORIZED) {
Arik Nemtsov2fec3d22013-03-12 17:19:37 +02004689 ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004690 if (ret < 0)
4691 return ret;
4692
4693 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
Arik Nemtsov2fec3d22013-03-12 17:19:37 +02004694 wl_sta->hlid);
Eliad Peller29936262012-11-20 13:20:06 +02004695 if (ret)
4696 return ret;
Eliad Peller426001a2012-11-26 18:05:45 +02004697
4698 wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004699 }
4700
Eliad Peller9fd6f212012-03-04 10:55:48 +02004701 /* Authorize station */
4702 if (is_sta &&
4703 new_state == IEEE80211_STA_AUTHORIZED) {
4704 set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
Eliad Peller29936262012-11-20 13:20:06 +02004705 ret = wl12xx_set_authorized(wl, wlvif);
4706 if (ret)
4707 return ret;
Eliad Peller9fd6f212012-03-04 10:55:48 +02004708 }
4709
4710 if (is_sta &&
4711 old_state == IEEE80211_STA_AUTHORIZED &&
4712 new_state == IEEE80211_STA_ASSOC) {
4713 clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
Eliad Peller3230f352012-11-20 13:20:01 +02004714 clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags);
Eliad Peller9fd6f212012-03-04 10:55:48 +02004715 }
4716
Eliad Peller29936262012-11-20 13:20:06 +02004717 /* clear ROCs on failure or authorization */
4718 if (is_sta &&
4719 (new_state == IEEE80211_STA_AUTHORIZED ||
4720 new_state == IEEE80211_STA_NOTEXIST)) {
4721 if (test_bit(wlvif->role_id, wl->roc_map))
4722 wl12xx_croc(wl, wlvif->role_id);
4723 }
4724
4725 if (is_sta &&
4726 old_state == IEEE80211_STA_NOTEXIST &&
4727 new_state == IEEE80211_STA_NONE) {
4728 if (find_first_bit(wl->roc_map,
4729 WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) {
4730 WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID);
4731 wl12xx_roc(wl, wlvif, wlvif->role_id,
4732 wlvif->band, wlvif->channel);
4733 }
4734 }
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004735 return 0;
4736}
4737
4738static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
4739 struct ieee80211_vif *vif,
4740 struct ieee80211_sta *sta,
4741 enum ieee80211_sta_state old_state,
4742 enum ieee80211_sta_state new_state)
4743{
4744 struct wl1271 *wl = hw->priv;
4745 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4746 int ret;
4747
4748 wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
4749 sta->aid, old_state, new_state);
4750
4751 mutex_lock(&wl->mutex);
4752
Ido Yariv4cc53382012-07-24 19:18:49 +03004753 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004754 ret = -EBUSY;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004755 goto out;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004756 }
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004757
Ido Yariva6208652011-03-01 15:14:41 +02004758 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004759 if (ret < 0)
4760 goto out;
4761
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004762 ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004763
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004764 wl1271_ps_elp_sleep(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004765out:
4766 mutex_unlock(&wl->mutex);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004767 if (new_state < old_state)
4768 return 0;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004769 return ret;
4770}
4771
Luciano Coelho4623ec72011-03-21 19:26:41 +02004772static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4773 struct ieee80211_vif *vif,
4774 enum ieee80211_ampdu_mlme_action action,
4775 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4776 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004777{
4778 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004779 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004780 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004781 u8 hlid, *ba_bitmap;
4782
4783 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4784 tid);
4785
4786 /* sanity check - the fields in FW are only 8bits wide */
4787 if (WARN_ON(tid > 0xFF))
4788 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004789
4790 mutex_lock(&wl->mutex);
4791
Ido Yariv4cc53382012-07-24 19:18:49 +03004792 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004793 ret = -EAGAIN;
4794 goto out;
4795 }
4796
Eliad Peller536129c2011-10-05 11:55:45 +02004797 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004798 hlid = wlvif->sta.hlid;
Eliad Peller536129c2011-10-05 11:55:45 +02004799 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004800 struct wl1271_station *wl_sta;
4801
4802 wl_sta = (struct wl1271_station *)sta->drv_priv;
4803 hlid = wl_sta->hlid;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004804 } else {
4805 ret = -EINVAL;
4806 goto out;
4807 }
4808
Arik Nemtsov9ae5d8d2012-11-28 11:42:45 +02004809 ba_bitmap = &wl->links[hlid].ba_bitmap;
4810
Ido Yariva6208652011-03-01 15:14:41 +02004811 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004812 if (ret < 0)
4813 goto out;
4814
Shahar Levi70559a02011-05-22 16:10:22 +03004815 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4816 tid, action);
4817
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004818 switch (action) {
4819 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004820 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004821 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004822 break;
4823 }
4824
Igal Chernobelskyd21553f2013-03-12 17:19:35 +02004825 if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004826 ret = -EBUSY;
4827 wl1271_error("exceeded max RX BA sessions");
4828 break;
4829 }
4830
4831 if (*ba_bitmap & BIT(tid)) {
4832 ret = -EINVAL;
4833 wl1271_error("cannot enable RX BA session on active "
4834 "tid: %d", tid);
4835 break;
4836 }
4837
4838 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4839 hlid);
4840 if (!ret) {
4841 *ba_bitmap |= BIT(tid);
4842 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004843 }
4844 break;
4845
4846 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004847 if (!(*ba_bitmap & BIT(tid))) {
Arik Nemtsovc9549102012-06-06 10:48:56 +03004848 /*
4849 * this happens on reconfig - so only output a debug
4850 * message for now, and don't fail the function.
4851 */
4852 wl1271_debug(DEBUG_MAC80211,
4853 "no active RX BA session on tid: %d",
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004854 tid);
Arik Nemtsovc9549102012-06-06 10:48:56 +03004855 ret = 0;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004856 break;
4857 }
4858
4859 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4860 hlid);
4861 if (!ret) {
4862 *ba_bitmap &= ~BIT(tid);
4863 wl->ba_rx_session_count--;
4864 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004865 break;
4866
4867 /*
4868 * The BA initiator session management in FW independently.
4869 * Falling break here on purpose for all TX APDU commands.
4870 */
4871 case IEEE80211_AMPDU_TX_START:
Johannes Berg18b559d2012-07-18 13:51:25 +02004872 case IEEE80211_AMPDU_TX_STOP_CONT:
4873 case IEEE80211_AMPDU_TX_STOP_FLUSH:
4874 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004875 case IEEE80211_AMPDU_TX_OPERATIONAL:
4876 ret = -EINVAL;
4877 break;
4878
4879 default:
4880 wl1271_error("Incorrect ampdu action id=%x\n", action);
4881 ret = -EINVAL;
4882 }
4883
4884 wl1271_ps_elp_sleep(wl);
4885
4886out:
4887 mutex_unlock(&wl->mutex);
4888
4889 return ret;
4890}
4891
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004892static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4893 struct ieee80211_vif *vif,
4894 const struct cfg80211_bitrate_mask *mask)
4895{
Eliad Peller83587502011-10-10 10:12:53 +02004896 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004897 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004898 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004899
4900 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4901 mask->control[NL80211_BAND_2GHZ].legacy,
4902 mask->control[NL80211_BAND_5GHZ].legacy);
4903
4904 mutex_lock(&wl->mutex);
4905
Arik Nemtsov091185d2012-07-03 09:11:03 +03004906 for (i = 0; i < WLCORE_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004907 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004908 wl1271_tx_enabled_rates_get(wl,
4909 mask->control[i].legacy,
4910 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004911
Ido Yariv4cc53382012-07-24 19:18:49 +03004912 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004913 goto out;
4914
4915 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4916 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4917
4918 ret = wl1271_ps_elp_wakeup(wl);
4919 if (ret < 0)
4920 goto out;
4921
4922 wl1271_set_band_rate(wl, wlvif);
4923 wlvif->basic_rate =
4924 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4925 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4926
4927 wl1271_ps_elp_sleep(wl);
4928 }
4929out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004930 mutex_unlock(&wl->mutex);
4931
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004932 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004933}
4934
Shahar Levi6d158ff2011-09-08 13:01:33 +03004935static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4936 struct ieee80211_channel_switch *ch_switch)
4937{
4938 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004939 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004940 int ret;
4941
4942 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4943
Arik Nemtsovb9239b62012-02-28 00:41:33 +02004944 wl1271_tx_flush(wl);
4945
Shahar Levi6d158ff2011-09-08 13:01:33 +03004946 mutex_lock(&wl->mutex);
4947
Ido Yariv4cc53382012-07-24 19:18:49 +03004948 if (unlikely(wl->state == WLCORE_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004949 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4950 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4951 ieee80211_chswitch_done(vif, false);
4952 }
4953 goto out;
Ido Yariv4cc53382012-07-24 19:18:49 +03004954 } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
4955 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004956 }
4957
4958 ret = wl1271_ps_elp_wakeup(wl);
4959 if (ret < 0)
4960 goto out;
4961
Eliad Peller52630c52011-10-10 10:13:08 +02004962 /* TODO: change mac80211 to pass vif as param */
4963 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Pellerc50a2822012-11-22 18:06:19 +02004964 unsigned long delay_usec;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004965
Eliad Pellerfcab1892012-11-22 18:06:18 +02004966 ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
Eliad Pellerc50a2822012-11-22 18:06:19 +02004967 if (ret)
4968 goto out_sleep;
4969
4970 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4971
4972 /* indicate failure 5 seconds after channel switch time */
4973 delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
4974 ch_switch->count;
4975 ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
4976 usecs_to_jiffies(delay_usec) +
4977 msecs_to_jiffies(5000));
Eliad Peller52630c52011-10-10 10:13:08 +02004978 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004979
Eliad Pellerc50a2822012-11-22 18:06:19 +02004980out_sleep:
Shahar Levi6d158ff2011-09-08 13:01:33 +03004981 wl1271_ps_elp_sleep(wl);
4982
4983out:
4984 mutex_unlock(&wl->mutex);
4985}
4986
Johannes Berg39ecc012013-02-13 12:11:00 +01004987static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
Eliad Pellerd8ae5a22012-06-25 13:52:33 +03004988{
4989 struct wl1271 *wl = hw->priv;
4990
4991 wl1271_tx_flush(wl);
4992}
4993
Eliad Pellerdabf37d2012-11-20 13:20:03 +02004994static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
4995 struct ieee80211_vif *vif,
4996 struct ieee80211_channel *chan,
Ilan Peerd339d5c2013-02-12 09:34:13 +02004997 int duration,
4998 enum ieee80211_roc_type type)
Eliad Pellerdabf37d2012-11-20 13:20:03 +02004999{
5000 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5001 struct wl1271 *wl = hw->priv;
5002 int channel, ret = 0;
5003
5004 channel = ieee80211_frequency_to_channel(chan->center_freq);
5005
5006 wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)",
5007 channel, wlvif->role_id);
5008
5009 mutex_lock(&wl->mutex);
5010
5011 if (unlikely(wl->state != WLCORE_STATE_ON))
5012 goto out;
5013
5014 /* return EBUSY if we can't ROC right now */
5015 if (WARN_ON(wl->roc_vif ||
5016 find_first_bit(wl->roc_map,
5017 WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) {
5018 ret = -EBUSY;
5019 goto out;
5020 }
5021
5022 ret = wl1271_ps_elp_wakeup(wl);
5023 if (ret < 0)
5024 goto out;
5025
5026 ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
5027 if (ret < 0)
5028 goto out_sleep;
5029
5030 wl->roc_vif = vif;
5031 ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
5032 msecs_to_jiffies(duration));
5033out_sleep:
5034 wl1271_ps_elp_sleep(wl);
5035out:
5036 mutex_unlock(&wl->mutex);
5037 return ret;
5038}
5039
5040static int __wlcore_roc_completed(struct wl1271 *wl)
5041{
5042 struct wl12xx_vif *wlvif;
5043 int ret;
5044
5045 /* already completed */
5046 if (unlikely(!wl->roc_vif))
5047 return 0;
5048
5049 wlvif = wl12xx_vif_to_data(wl->roc_vif);
5050
5051 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
5052 return -EBUSY;
5053
5054 ret = wl12xx_stop_dev(wl, wlvif);
5055 if (ret < 0)
5056 return ret;
5057
5058 wl->roc_vif = NULL;
5059
5060 return 0;
5061}
5062
5063static int wlcore_roc_completed(struct wl1271 *wl)
5064{
5065 int ret;
5066
5067 wl1271_debug(DEBUG_MAC80211, "roc complete");
5068
5069 mutex_lock(&wl->mutex);
5070
5071 if (unlikely(wl->state != WLCORE_STATE_ON)) {
5072 ret = -EBUSY;
5073 goto out;
5074 }
5075
5076 ret = wl1271_ps_elp_wakeup(wl);
5077 if (ret < 0)
5078 goto out;
5079
5080 ret = __wlcore_roc_completed(wl);
5081
5082 wl1271_ps_elp_sleep(wl);
5083out:
5084 mutex_unlock(&wl->mutex);
5085
5086 return ret;
5087}
5088
5089static void wlcore_roc_complete_work(struct work_struct *work)
5090{
5091 struct delayed_work *dwork;
5092 struct wl1271 *wl;
5093 int ret;
5094
5095 dwork = container_of(work, struct delayed_work, work);
5096 wl = container_of(dwork, struct wl1271, roc_complete_work);
5097
5098 ret = wlcore_roc_completed(wl);
5099 if (!ret)
5100 ieee80211_remain_on_channel_expired(wl->hw);
5101}
5102
5103static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
5104{
5105 struct wl1271 *wl = hw->priv;
5106
5107 wl1271_debug(DEBUG_MAC80211, "mac80211 croc");
5108
5109 /* TODO: per-vif */
5110 wl1271_tx_flush(wl);
5111
5112 /*
5113 * we can't just flush_work here, because it might deadlock
5114 * (as we might get called from the same workqueue)
5115 */
5116 cancel_delayed_work_sync(&wl->roc_complete_work);
5117 wlcore_roc_completed(wl);
5118
5119 return 0;
5120}
5121
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02005122static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
5123 struct ieee80211_vif *vif,
5124 struct ieee80211_sta *sta,
5125 u32 changed)
5126{
5127 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5128 struct wl1271 *wl = hw->priv;
5129
5130 wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
5131}
5132
Nadim Zubidat0a9ffac2013-03-12 17:19:39 +02005133static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
5134 struct ieee80211_vif *vif,
5135 struct ieee80211_sta *sta,
5136 s8 *rssi_dbm)
5137{
5138 struct wl1271 *wl = hw->priv;
5139 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5140 int ret = 0;
5141
5142 wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
5143
5144 mutex_lock(&wl->mutex);
5145
5146 if (unlikely(wl->state != WLCORE_STATE_ON))
5147 goto out;
5148
5149 ret = wl1271_ps_elp_wakeup(wl);
5150 if (ret < 0)
5151 goto out_sleep;
5152
5153 ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
5154 if (ret < 0)
5155 goto out_sleep;
5156
5157out_sleep:
5158 wl1271_ps_elp_sleep(wl);
5159
5160out:
5161 mutex_unlock(&wl->mutex);
5162
5163 return ret;
5164}
5165
Arik Nemtsov33437892011-04-26 23:35:39 +03005166static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
5167{
5168 struct wl1271 *wl = hw->priv;
5169 bool ret = false;
5170
5171 mutex_lock(&wl->mutex);
5172
Ido Yariv4cc53382012-07-24 19:18:49 +03005173 if (unlikely(wl->state != WLCORE_STATE_ON))
Arik Nemtsov33437892011-04-26 23:35:39 +03005174 goto out;
5175
5176 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03005177 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03005178out:
5179 mutex_unlock(&wl->mutex);
5180
5181 return ret;
5182}
5183
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005184/* can't be const, mac80211 writes to this */
5185static struct ieee80211_rate wl1271_rates[] = {
5186 { .bitrate = 10,
5187 .hw_value = CONF_HW_BIT_RATE_1MBPS,
5188 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
5189 { .bitrate = 20,
5190 .hw_value = CONF_HW_BIT_RATE_2MBPS,
5191 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
5192 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5193 { .bitrate = 55,
5194 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
5195 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
5196 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5197 { .bitrate = 110,
5198 .hw_value = CONF_HW_BIT_RATE_11MBPS,
5199 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
5200 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5201 { .bitrate = 60,
5202 .hw_value = CONF_HW_BIT_RATE_6MBPS,
5203 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
5204 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005205 .hw_value = CONF_HW_BIT_RATE_9MBPS,
5206 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005207 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005208 .hw_value = CONF_HW_BIT_RATE_12MBPS,
5209 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005210 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005211 .hw_value = CONF_HW_BIT_RATE_18MBPS,
5212 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005213 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005214 .hw_value = CONF_HW_BIT_RATE_24MBPS,
5215 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005216 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005217 .hw_value = CONF_HW_BIT_RATE_36MBPS,
5218 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005219 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005220 .hw_value = CONF_HW_BIT_RATE_48MBPS,
5221 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005222 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005223 .hw_value = CONF_HW_BIT_RATE_54MBPS,
5224 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005225};
5226
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01005227/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005228static struct ieee80211_channel wl1271_channels[] = {
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005229 { .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR },
5230 { .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR },
5231 { .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR },
5232 { .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR },
5233 { .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR },
5234 { .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR },
5235 { .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR },
5236 { .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR },
5237 { .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR },
5238 { .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR },
5239 { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR },
5240 { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR },
5241 { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR },
5242 { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005243};
5244
5245/* can't be const, mac80211 writes to this */
5246static struct ieee80211_supported_band wl1271_band_2ghz = {
5247 .channels = wl1271_channels,
5248 .n_channels = ARRAY_SIZE(wl1271_channels),
5249 .bitrates = wl1271_rates,
5250 .n_bitrates = ARRAY_SIZE(wl1271_rates),
5251};
5252
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005253/* 5 GHz data rates for WL1273 */
5254static struct ieee80211_rate wl1271_rates_5ghz[] = {
5255 { .bitrate = 60,
5256 .hw_value = CONF_HW_BIT_RATE_6MBPS,
5257 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
5258 { .bitrate = 90,
5259 .hw_value = CONF_HW_BIT_RATE_9MBPS,
5260 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
5261 { .bitrate = 120,
5262 .hw_value = CONF_HW_BIT_RATE_12MBPS,
5263 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
5264 { .bitrate = 180,
5265 .hw_value = CONF_HW_BIT_RATE_18MBPS,
5266 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
5267 { .bitrate = 240,
5268 .hw_value = CONF_HW_BIT_RATE_24MBPS,
5269 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
5270 { .bitrate = 360,
5271 .hw_value = CONF_HW_BIT_RATE_36MBPS,
5272 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
5273 { .bitrate = 480,
5274 .hw_value = CONF_HW_BIT_RATE_48MBPS,
5275 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
5276 { .bitrate = 540,
5277 .hw_value = CONF_HW_BIT_RATE_54MBPS,
5278 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
5279};
5280
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01005281/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005282static struct ieee80211_channel wl1271_channels_5ghz[] = {
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005283 { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
5284 { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
5285 { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
5286 { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
5287 { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
5288 { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
5289 { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
5290 { .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR },
5291 { .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR },
5292 { .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR },
5293 { .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR },
5294 { .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR },
5295 { .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR },
5296 { .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR },
5297 { .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR },
5298 { .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR },
5299 { .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR },
5300 { .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR },
5301 { .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR },
5302 { .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR },
5303 { .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR },
5304 { .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR },
5305 { .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR },
5306 { .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR },
5307 { .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR },
5308 { .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR },
5309 { .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR },
5310 { .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR },
5311 { .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR },
5312 { .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR },
5313 { .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR },
5314 { .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR },
5315 { .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR },
5316 { .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005317};
5318
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005319static struct ieee80211_supported_band wl1271_band_5ghz = {
5320 .channels = wl1271_channels_5ghz,
5321 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
5322 .bitrates = wl1271_rates_5ghz,
5323 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005324};
5325
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005326static const struct ieee80211_ops wl1271_ops = {
5327 .start = wl1271_op_start,
Ido Yarivc24ec832012-06-26 21:08:58 +03005328 .stop = wlcore_op_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005329 .add_interface = wl1271_op_add_interface,
5330 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02005331 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04005332#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03005333 .suspend = wl1271_op_suspend,
5334 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04005335#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005336 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03005337 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005338 .configure_filter = wl1271_op_configure_filter,
5339 .tx = wl1271_op_tx,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03005340 .set_key = wlcore_op_set_key,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005341 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03005342 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03005343 .sched_scan_start = wl1271_op_sched_scan_start,
5344 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005345 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01005346 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005347 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02005348 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03005349 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04005350 .get_survey = wl1271_op_get_survey,
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02005351 .sta_state = wl12xx_op_sta_state,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01005352 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03005353 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03005354 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03005355 .channel_switch = wl12xx_op_channel_switch,
Eliad Pellerd8ae5a22012-06-25 13:52:33 +03005356 .flush = wlcore_op_flush,
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005357 .remain_on_channel = wlcore_op_remain_on_channel,
5358 .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
Eliad Pellerb6970ee2012-11-20 13:20:05 +02005359 .add_chanctx = wlcore_op_add_chanctx,
5360 .remove_chanctx = wlcore_op_remove_chanctx,
5361 .change_chanctx = wlcore_op_change_chanctx,
5362 .assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
5363 .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02005364 .sta_rc_update = wlcore_op_sta_rc_update,
Nadim Zubidat0a9ffac2013-03-12 17:19:39 +02005365 .get_rssi = wlcore_op_get_rssi,
Kalle Valoc8c90872010-02-18 13:25:53 +02005366 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005367};
5368
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005369
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005370u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005371{
5372 u8 idx;
5373
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005374 BUG_ON(band >= 2);
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005375
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005376 if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005377 wl1271_error("Illegal RX rate from HW: %d", rate);
5378 return 0;
5379 }
5380
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005381 idx = wl->band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005382 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
5383 wl1271_error("Unsupported RX rate from HW: %d", rate);
5384 return 0;
5385 }
5386
5387 return idx;
5388}
5389
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005390static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
5391 struct device_attribute *attr,
5392 char *buf)
5393{
5394 struct wl1271 *wl = dev_get_drvdata(dev);
5395 ssize_t len;
5396
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02005397 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005398
5399 mutex_lock(&wl->mutex);
5400 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
5401 wl->sg_enabled);
5402 mutex_unlock(&wl->mutex);
5403
5404 return len;
5405
5406}
5407
5408static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
5409 struct device_attribute *attr,
5410 const char *buf, size_t count)
5411{
5412 struct wl1271 *wl = dev_get_drvdata(dev);
5413 unsigned long res;
5414 int ret;
5415
Luciano Coelho6277ed62011-04-01 17:49:54 +03005416 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005417 if (ret < 0) {
5418 wl1271_warning("incorrect value written to bt_coex_mode");
5419 return count;
5420 }
5421
5422 mutex_lock(&wl->mutex);
5423
5424 res = !!res;
5425
5426 if (res == wl->sg_enabled)
5427 goto out;
5428
5429 wl->sg_enabled = res;
5430
Ido Yariv4cc53382012-07-24 19:18:49 +03005431 if (unlikely(wl->state != WLCORE_STATE_ON))
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005432 goto out;
5433
Ido Yariva6208652011-03-01 15:14:41 +02005434 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005435 if (ret < 0)
5436 goto out;
5437
5438 wl1271_acx_sg_enable(wl, wl->sg_enabled);
5439 wl1271_ps_elp_sleep(wl);
5440
5441 out:
5442 mutex_unlock(&wl->mutex);
5443 return count;
5444}
5445
5446static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
5447 wl1271_sysfs_show_bt_coex_state,
5448 wl1271_sysfs_store_bt_coex_state);
5449
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005450static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
5451 struct device_attribute *attr,
5452 char *buf)
5453{
5454 struct wl1271 *wl = dev_get_drvdata(dev);
5455 ssize_t len;
5456
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02005457 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005458
5459 mutex_lock(&wl->mutex);
5460 if (wl->hw_pg_ver >= 0)
5461 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
5462 else
5463 len = snprintf(buf, len, "n/a\n");
5464 mutex_unlock(&wl->mutex);
5465
5466 return len;
5467}
5468
Gery Kahn6f07b722011-07-18 14:21:49 +03005469static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005470 wl1271_sysfs_show_hw_pg_ver, NULL);
5471
Ido Yariv95dac04f2011-06-06 14:57:06 +03005472static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
5473 struct bin_attribute *bin_attr,
5474 char *buffer, loff_t pos, size_t count)
5475{
5476 struct device *dev = container_of(kobj, struct device, kobj);
5477 struct wl1271 *wl = dev_get_drvdata(dev);
5478 ssize_t len;
5479 int ret;
5480
5481 ret = mutex_lock_interruptible(&wl->mutex);
5482 if (ret < 0)
5483 return -ERESTARTSYS;
5484
5485 /* Let only one thread read the log at a time, blocking others */
5486 while (wl->fwlog_size == 0) {
5487 DEFINE_WAIT(wait);
5488
5489 prepare_to_wait_exclusive(&wl->fwlog_waitq,
5490 &wait,
5491 TASK_INTERRUPTIBLE);
5492
5493 if (wl->fwlog_size != 0) {
5494 finish_wait(&wl->fwlog_waitq, &wait);
5495 break;
5496 }
5497
5498 mutex_unlock(&wl->mutex);
5499
5500 schedule();
5501 finish_wait(&wl->fwlog_waitq, &wait);
5502
5503 if (signal_pending(current))
5504 return -ERESTARTSYS;
5505
5506 ret = mutex_lock_interruptible(&wl->mutex);
5507 if (ret < 0)
5508 return -ERESTARTSYS;
5509 }
5510
5511 /* Check if the fwlog is still valid */
5512 if (wl->fwlog_size < 0) {
5513 mutex_unlock(&wl->mutex);
5514 return 0;
5515 }
5516
5517 /* Seeking is not supported - old logs are not kept. Disregard pos. */
5518 len = min(count, (size_t)wl->fwlog_size);
5519 wl->fwlog_size -= len;
5520 memcpy(buffer, wl->fwlog, len);
5521
5522 /* Make room for new messages */
5523 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
5524
5525 mutex_unlock(&wl->mutex);
5526
5527 return len;
5528}
5529
5530static struct bin_attribute fwlog_attr = {
5531 .attr = {.name = "fwlog", .mode = S_IRUSR},
5532 .read = wl1271_sysfs_read_fwlog,
5533};
5534
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005535static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
Luciano Coelho5e037e72011-12-23 09:32:17 +02005536{
5537 int i;
5538
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005539 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x",
5540 oui, nic);
Luciano Coelho5e037e72011-12-23 09:32:17 +02005541
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005542 if (nic + WLCORE_NUM_MAC_ADDRESSES - wl->num_mac_addr > 0xffffff)
Luciano Coelho5e037e72011-12-23 09:32:17 +02005543 wl1271_warning("NIC part of the MAC address wraps around!");
5544
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005545 for (i = 0; i < wl->num_mac_addr; i++) {
Luciano Coelho5e037e72011-12-23 09:32:17 +02005546 wl->addresses[i].addr[0] = (u8)(oui >> 16);
5547 wl->addresses[i].addr[1] = (u8)(oui >> 8);
5548 wl->addresses[i].addr[2] = (u8) oui;
5549 wl->addresses[i].addr[3] = (u8)(nic >> 16);
5550 wl->addresses[i].addr[4] = (u8)(nic >> 8);
5551 wl->addresses[i].addr[5] = (u8) nic;
5552 nic++;
5553 }
5554
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005555 /* we may be one address short at the most */
5556 WARN_ON(wl->num_mac_addr + 1 < WLCORE_NUM_MAC_ADDRESSES);
5557
5558 /*
5559 * turn on the LAA bit in the first address and use it as
5560 * the last address.
5561 */
5562 if (wl->num_mac_addr < WLCORE_NUM_MAC_ADDRESSES) {
5563 int idx = WLCORE_NUM_MAC_ADDRESSES - 1;
5564 memcpy(&wl->addresses[idx], &wl->addresses[0],
5565 sizeof(wl->addresses[0]));
5566 /* LAA bit */
5567 wl->addresses[idx].addr[2] |= BIT(1);
5568 }
5569
5570 wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES;
Luciano Coelho5e037e72011-12-23 09:32:17 +02005571 wl->hw->wiphy->addresses = wl->addresses;
5572}
5573
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005574static int wl12xx_get_hw_info(struct wl1271 *wl)
5575{
5576 int ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005577
5578 ret = wl12xx_set_power_on(wl);
5579 if (ret < 0)
Julia Lawall4fb4e0b2012-10-21 12:52:04 +02005580 return ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005581
Ido Yariv61343232012-06-18 15:50:21 +03005582 ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
5583 if (ret < 0)
5584 goto out;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005585
Luciano Coelho00782132011-11-29 13:38:37 +02005586 wl->fuse_oui_addr = 0;
5587 wl->fuse_nic_addr = 0;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005588
Ido Yariv61343232012-06-18 15:50:21 +03005589 ret = wl->ops->get_pg_ver(wl, &wl->hw_pg_ver);
5590 if (ret < 0)
5591 goto out;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005592
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03005593 if (wl->ops->get_mac)
Ido Yariv61343232012-06-18 15:50:21 +03005594 ret = wl->ops->get_mac(wl);
Luciano Coelho5e037e72011-12-23 09:32:17 +02005595
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005596out:
Ido Yariv61343232012-06-18 15:50:21 +03005597 wl1271_power_off(wl);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005598 return ret;
5599}
5600
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005601static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005602{
5603 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02005604 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005605
5606 if (wl->mac80211_registered)
5607 return 0;
5608
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005609 if (wl->nvs_len >= 12) {
Shahar Levibc765bf2011-03-06 16:32:10 +02005610 /* NOTE: The wl->nvs->nvs element must be first, in
5611 * order to simplify the casting, we assume it is at
5612 * the beginning of the wl->nvs structure.
5613 */
5614 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005615
Luciano Coelho5e037e72011-12-23 09:32:17 +02005616 oui_addr =
5617 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
5618 nic_addr =
5619 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005620 }
5621
Luciano Coelho5e037e72011-12-23 09:32:17 +02005622 /* if the MAC address is zeroed in the NVS derive from fuse */
5623 if (oui_addr == 0 && nic_addr == 0) {
5624 oui_addr = wl->fuse_oui_addr;
5625 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
5626 nic_addr = wl->fuse_nic_addr + 1;
5627 }
5628
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005629 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005630
5631 ret = ieee80211_register_hw(wl->hw);
5632 if (ret < 0) {
5633 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005634 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005635 }
5636
5637 wl->mac80211_registered = true;
5638
Eliad Pellerd60080a2010-11-24 12:53:16 +02005639 wl1271_debugfs_init(wl);
5640
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005641 wl1271_notice("loaded");
5642
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005643out:
5644 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005645}
5646
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005647static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005648{
Eliad Peller3fcdab72012-02-06 12:47:54 +02005649 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02005650 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005651
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005652 ieee80211_unregister_hw(wl->hw);
5653 wl->mac80211_registered = false;
5654
5655}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005656
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005657static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
5658 {
Arik Nemtsove7a6ba292012-08-02 22:00:34 +03005659 .max = 3,
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005660 .types = BIT(NL80211_IFTYPE_STATION),
5661 },
5662 {
5663 .max = 1,
5664 .types = BIT(NL80211_IFTYPE_AP) |
5665 BIT(NL80211_IFTYPE_P2P_GO) |
5666 BIT(NL80211_IFTYPE_P2P_CLIENT),
5667 },
5668};
5669
Arik Nemtsovde407502012-11-26 18:05:44 +02005670static struct ieee80211_iface_combination
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005671wlcore_iface_combinations[] = {
5672 {
Arik Nemtsove7a6ba292012-08-02 22:00:34 +03005673 .max_interfaces = 3,
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005674 .limits = wlcore_iface_limits,
5675 .n_limits = ARRAY_SIZE(wlcore_iface_limits),
5676 },
5677};
5678
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005679static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005680{
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005681 int i;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005682 static const u32 cipher_suites[] = {
5683 WLAN_CIPHER_SUITE_WEP40,
5684 WLAN_CIPHER_SUITE_WEP104,
5685 WLAN_CIPHER_SUITE_TKIP,
5686 WLAN_CIPHER_SUITE_CCMP,
5687 WL1271_CIPHER_SUITE_GEM,
5688 };
5689
Arik Nemtsov2c0133a2012-05-18 07:46:36 +03005690 /* The tx descriptor buffer */
5691 wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
5692
5693 if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
5694 wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005695
5696 /* unit us */
5697 /* FIXME: find a proper value */
5698 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005699 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005700
5701 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005702 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005703 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005704 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005705 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005706 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005707 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005708 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005709 IEEE80211_HW_AP_LINK_PS |
5710 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005711 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
Arik Nemtsov1c33db72012-11-30 00:48:03 +02005712 IEEE80211_HW_QUEUE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005713
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005714 wl->hw->wiphy->cipher_suites = cipher_suites;
5715 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5716
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005717 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005718 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5719 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005720 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005721 wl->hw->wiphy->max_sched_scan_ssids = 16;
5722 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005723 /*
5724 * Maximum length of elements in scanning probe request templates
5725 * should be the maximum length possible for a template, without
5726 * the IEEE80211 header of the template
5727 */
Ido Reisc08e3712012-02-02 13:54:27 +02005728 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005729 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005730
Ido Reisc08e3712012-02-02 13:54:27 +02005731 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005732 sizeof(struct ieee80211_header);
5733
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005734 wl->hw->wiphy->max_remain_on_channel_duration = 5000;
5735
Johannes Berg81ddbb52012-03-26 18:47:18 +02005736 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
5737 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
Eliad Peller1ec23f72011-08-25 14:26:54 +03005738
Luciano Coelho4a31c112011-03-21 23:16:14 +02005739 /* make sure all our channels fit in the scanned_ch bitmask */
5740 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5741 ARRAY_SIZE(wl1271_channels_5ghz) >
5742 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005743 /*
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005744 * clear channel flags from the previous usage
5745 * and restore max_power & max_antenna_gain values.
5746 */
5747 for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) {
5748 wl1271_band_2ghz.channels[i].flags = 0;
5749 wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
5750 wl1271_band_2ghz.channels[i].max_antenna_gain = 0;
5751 }
5752
5753 for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) {
5754 wl1271_band_5ghz.channels[i].flags = 0;
5755 wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
5756 wl1271_band_5ghz.channels[i].max_antenna_gain = 0;
5757 }
5758
5759 /*
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005760 * We keep local copies of the band structs because we need to
5761 * modify them on a per-device basis.
5762 */
5763 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5764 sizeof(wl1271_band_2ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005765 memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
5766 &wl->ht_cap[IEEE80211_BAND_2GHZ],
5767 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005768 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5769 sizeof(wl1271_band_5ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005770 memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
5771 &wl->ht_cap[IEEE80211_BAND_5GHZ],
5772 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005773
5774 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5775 &wl->bands[IEEE80211_BAND_2GHZ];
5776 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5777 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005778
Arik Nemtsov1c33db72012-11-30 00:48:03 +02005779 /*
5780 * allow 4 queues per mac address we support +
5781 * 1 cab queue per mac + one global offchannel Tx queue
5782 */
5783 wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1;
5784
5785 /* the last queue is the offchannel queue */
5786 wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005787 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005788
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005789 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5790
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005791 /* the FW answers probe-requests in AP-mode */
5792 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5793 wl->hw->wiphy->probe_resp_offload =
5794 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5795 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5796 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5797
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005798 /* allowed interface combinations */
Arik Nemtsovde407502012-11-26 18:05:44 +02005799 wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005800 wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
5801 wl->hw->wiphy->n_iface_combinations =
5802 ARRAY_SIZE(wlcore_iface_combinations);
5803
Felipe Balbia390e852011-10-06 10:07:44 +03005804 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005805
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005806 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005807 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005808
Arik Nemtsovba421f82012-01-06 00:05:51 +02005809 wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size;
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005810
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005811 return 0;
5812}
5813
Eliad Pellerc50a2822012-11-22 18:06:19 +02005814struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
5815 u32 mbox_size)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005816{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005817 struct ieee80211_hw *hw;
5818 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005819 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005820 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005821
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005822 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005823
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005824 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5825 if (!hw) {
5826 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005827 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005828 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005829 }
5830
5831 wl = hw->priv;
5832 memset(wl, 0, sizeof(*wl));
5833
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005834 wl->priv = kzalloc(priv_size, GFP_KERNEL);
5835 if (!wl->priv) {
5836 wl1271_error("could not alloc wl priv");
5837 ret = -ENOMEM;
5838 goto err_priv_alloc;
5839 }
5840
Eliad Peller87627212011-10-10 10:12:54 +02005841 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005843 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005844
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005845 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005846 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005847 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5848
Ido Yariva6208652011-03-01 15:14:41 +02005849 skb_queue_head_init(&wl->deferred_rx_queue);
5850 skb_queue_head_init(&wl->deferred_tx_queue);
5851
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005852 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005853 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005854 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5855 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5856 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005857 INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02005858 INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005859
Eliad Peller92ef8962011-06-07 12:50:46 +03005860 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5861 if (!wl->freezable_wq) {
5862 ret = -ENOMEM;
5863 goto err_hw;
5864 }
5865
Luciano Coelho8f6ac532013-05-04 01:06:11 +03005866 wl->channel = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005867 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005868 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005869 wl->band = IEEE80211_BAND_2GHZ;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03005870 wl->channel_type = NL80211_CHAN_NO_HT;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005871 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005872 wl->sg_enabled = true;
Arik Nemtsov66340e52012-06-10 17:09:22 +03005873 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Luciano Coelhoc108c902012-11-26 18:05:49 +02005874 wl->recovery_count = 0;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005875 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005876 wl->ap_ps_map = 0;
5877 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005878 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005879 wl->platform_quirks = 0;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005880 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005881 wl->active_sta_count = 0;
Arik Nemtsov9a100962012-11-28 11:42:42 +02005882 wl->active_link_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005883 wl->fwlog_size = 0;
5884 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005885
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005886 /* The system link is always allocated */
5887 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5888
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005889 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Arik Nemtsov72b06242011-12-07 21:21:51 +02005890 for (i = 0; i < wl->num_tx_desc; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005891 wl->tx_frames[i] = NULL;
5892
5893 spin_lock_init(&wl->wl_lock);
5894
Ido Yariv4cc53382012-07-24 19:18:49 +03005895 wl->state = WLCORE_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005896 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005897 mutex_init(&wl->mutex);
Arik Nemtsov2c388492012-05-18 07:46:39 +03005898 mutex_init(&wl->flush_mutex);
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005899 init_completion(&wl->nvs_loading_complete);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005900
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005901 order = get_order(aggr_buf_size);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005902 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5903 if (!wl->aggr_buf) {
5904 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005905 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005906 }
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005907 wl->aggr_buf_size = aggr_buf_size;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005908
Ido Yariv990f5de2011-03-31 10:06:59 +02005909 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5910 if (!wl->dummy_packet) {
5911 ret = -ENOMEM;
5912 goto err_aggr;
5913 }
5914
Ido Yariv95dac04f2011-06-06 14:57:06 +03005915 /* Allocate one page for the FW log */
5916 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5917 if (!wl->fwlog) {
5918 ret = -ENOMEM;
5919 goto err_dummy_packet;
5920 }
5921
Eliad Pellerc50a2822012-11-22 18:06:19 +02005922 wl->mbox_size = mbox_size;
5923 wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA);
Mircea Gherzan690142e2012-03-17 18:41:53 +01005924 if (!wl->mbox) {
5925 ret = -ENOMEM;
5926 goto err_fwlog;
5927 }
5928
Ido Yariv2e07d022012-11-28 11:42:49 +02005929 wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL);
5930 if (!wl->buffer_32) {
5931 ret = -ENOMEM;
5932 goto err_mbox;
5933 }
5934
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005935 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005936
Ido Yariv2e07d022012-11-28 11:42:49 +02005937err_mbox:
5938 kfree(wl->mbox);
5939
Mircea Gherzan690142e2012-03-17 18:41:53 +01005940err_fwlog:
5941 free_page((unsigned long)wl->fwlog);
5942
Ido Yariv990f5de2011-03-31 10:06:59 +02005943err_dummy_packet:
5944 dev_kfree_skb(wl->dummy_packet);
5945
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005946err_aggr:
5947 free_pages((unsigned long)wl->aggr_buf, order);
5948
Eliad Peller92ef8962011-06-07 12:50:46 +03005949err_wq:
5950 destroy_workqueue(wl->freezable_wq);
5951
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005952err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005953 wl1271_debugfs_exit(wl);
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005954 kfree(wl->priv);
5955
5956err_priv_alloc:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005957 ieee80211_free_hw(hw);
5958
5959err_hw_alloc:
5960
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005961 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005962}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005963EXPORT_SYMBOL_GPL(wlcore_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005964
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005965int wlcore_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005966{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005967 /* Unblock any fwlog readers */
5968 mutex_lock(&wl->mutex);
5969 wl->fwlog_size = -1;
5970 wake_up_interruptible_all(&wl->fwlog_waitq);
5971 mutex_unlock(&wl->mutex);
5972
Felipe Balbif79f8902011-10-06 13:05:25 +03005973 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005974
Felipe Balbif79f8902011-10-06 13:05:25 +03005975 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005976
Felipe Balbif79f8902011-10-06 13:05:25 +03005977 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv2e07d022012-11-28 11:42:49 +02005978 kfree(wl->buffer_32);
Eliad Pellera8e27822012-11-19 17:14:06 +02005979 kfree(wl->mbox);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005980 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005981 dev_kfree_skb(wl->dummy_packet);
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005982 free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005983
5984 wl1271_debugfs_exit(wl);
5985
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005986 vfree(wl->fw);
5987 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005988 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005989 kfree(wl->nvs);
5990 wl->nvs = NULL;
5991
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03005992 kfree(wl->fw_status_1);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005993 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005994 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005995
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005996 kfree(wl->priv);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005997 ieee80211_free_hw(wl->hw);
5998
5999 return 0;
6000}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02006001EXPORT_SYMBOL_GPL(wlcore_free_hw);
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02006002
Johannes Berg964dc9e2013-06-03 17:25:34 +02006003#ifdef CONFIG_PM
6004static const struct wiphy_wowlan_support wlcore_wowlan_support = {
6005 .flags = WIPHY_WOWLAN_ANY,
6006 .n_patterns = WL1271_MAX_RX_FILTERS,
6007 .pattern_min_len = 1,
6008 .pattern_max_len = WL1271_RX_FILTER_MAX_PATTERN_SIZE,
6009};
6010#endif
6011
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006012static void wlcore_nvs_cb(const struct firmware *fw, void *context)
Felipe Balbice2a2172011-10-05 14:12:55 +03006013{
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006014 struct wl1271 *wl = context;
6015 struct platform_device *pdev = wl->pdev;
Luciano Coelhoafb43e62013-01-25 11:57:48 +02006016 struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
6017 struct wl12xx_platform_data *pdata = pdev_data->pdata;
Felipe Balbia390e852011-10-06 10:07:44 +03006018 unsigned long irqflags;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02006019 int ret;
Felipe Balbia390e852011-10-06 10:07:44 +03006020
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006021 if (fw) {
6022 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
6023 if (!wl->nvs) {
6024 wl1271_error("Could not allocate nvs data");
6025 goto out;
6026 }
6027 wl->nvs_len = fw->size;
6028 } else {
6029 wl1271_debug(DEBUG_BOOT, "Could not get nvs file %s",
6030 WL12XX_NVS_NAME);
6031 wl->nvs = NULL;
6032 wl->nvs_len = 0;
Felipe Balbia390e852011-10-06 10:07:44 +03006033 }
6034
Ido Yariv3992eb22012-09-02 12:29:27 +03006035 ret = wl->ops->setup(wl);
6036 if (ret < 0)
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006037 goto out_free_nvs;
Ido Yariv3992eb22012-09-02 12:29:27 +03006038
Arik Nemtsov72b06242011-12-07 21:21:51 +02006039 BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
6040
Luciano Coelhoe87288f2011-12-05 16:12:54 +02006041 /* adjust some runtime configuration parameters */
6042 wlcore_adjust_conf(wl);
6043
Felipe Balbia390e852011-10-06 10:07:44 +03006044 wl->irq = platform_get_irq(pdev, 0);
Felipe Balbia390e852011-10-06 10:07:44 +03006045 wl->platform_quirks = pdata->platform_quirks;
Luciano Coelhoafb43e62013-01-25 11:57:48 +02006046 wl->if_ops = pdev_data->if_ops;
Felipe Balbia390e852011-10-06 10:07:44 +03006047
Felipe Balbia390e852011-10-06 10:07:44 +03006048 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
6049 irqflags = IRQF_TRIGGER_RISING;
6050 else
6051 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
6052
Luciano Coelho97236a02013-03-08 09:41:53 +02006053 ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
6054 irqflags, pdev->name, wl);
Felipe Balbia390e852011-10-06 10:07:44 +03006055 if (ret < 0) {
6056 wl1271_error("request_irq() failed: %d", ret);
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006057 goto out_free_nvs;
Felipe Balbia390e852011-10-06 10:07:44 +03006058 }
6059
Johannes Bergdfb89c52012-06-27 09:23:48 +02006060#ifdef CONFIG_PM
Felipe Balbia390e852011-10-06 10:07:44 +03006061 ret = enable_irq_wake(wl->irq);
6062 if (!ret) {
6063 wl->irq_wake_enabled = true;
6064 device_init_wakeup(wl->dev, 1);
Johannes Berg964dc9e2013-06-03 17:25:34 +02006065 if (pdata->pwr_in_suspend)
6066 wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
Felipe Balbia390e852011-10-06 10:07:44 +03006067 }
Johannes Bergdfb89c52012-06-27 09:23:48 +02006068#endif
Felipe Balbia390e852011-10-06 10:07:44 +03006069 disable_irq(wl->irq);
6070
Luciano Coelho4afc37a2012-05-10 12:14:02 +03006071 ret = wl12xx_get_hw_info(wl);
6072 if (ret < 0) {
6073 wl1271_error("couldn't get hw info");
Luciano Coelho8b425e62012-06-25 14:41:20 +03006074 goto out_irq;
Luciano Coelho4afc37a2012-05-10 12:14:02 +03006075 }
6076
6077 ret = wl->ops->identify_chip(wl);
6078 if (ret < 0)
Luciano Coelho8b425e62012-06-25 14:41:20 +03006079 goto out_irq;
Luciano Coelho4afc37a2012-05-10 12:14:02 +03006080
Felipe Balbia390e852011-10-06 10:07:44 +03006081 ret = wl1271_init_ieee80211(wl);
6082 if (ret)
6083 goto out_irq;
6084
6085 ret = wl1271_register_hw(wl);
6086 if (ret)
6087 goto out_irq;
6088
Felipe Balbif79f8902011-10-06 13:05:25 +03006089 /* Create sysfs file to control bt coex state */
6090 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
6091 if (ret < 0) {
6092 wl1271_error("failed to create sysfs file bt_coex_state");
Luciano Coelho8b425e62012-06-25 14:41:20 +03006093 goto out_unreg;
Felipe Balbif79f8902011-10-06 13:05:25 +03006094 }
6095
6096 /* Create sysfs file to get HW PG version */
6097 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
6098 if (ret < 0) {
6099 wl1271_error("failed to create sysfs file hw_pg_ver");
6100 goto out_bt_coex_state;
6101 }
6102
6103 /* Create sysfs file for the FW log */
6104 ret = device_create_bin_file(wl->dev, &fwlog_attr);
6105 if (ret < 0) {
6106 wl1271_error("failed to create sysfs file fwlog");
6107 goto out_hw_pg_ver;
6108 }
6109
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006110 wl->initialized = true;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02006111 goto out;
Felipe Balbia390e852011-10-06 10:07:44 +03006112
Felipe Balbif79f8902011-10-06 13:05:25 +03006113out_hw_pg_ver:
6114 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
6115
6116out_bt_coex_state:
6117 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
6118
Luciano Coelho8b425e62012-06-25 14:41:20 +03006119out_unreg:
6120 wl1271_unregister_hw(wl);
6121
Felipe Balbia390e852011-10-06 10:07:44 +03006122out_irq:
6123 free_irq(wl->irq, wl);
6124
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006125out_free_nvs:
6126 kfree(wl->nvs);
6127
Felipe Balbia390e852011-10-06 10:07:44 +03006128out:
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006129 release_firmware(fw);
6130 complete_all(&wl->nvs_loading_complete);
6131}
6132
Bill Pembertonb74324d2012-12-03 09:56:42 -05006133int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006134{
6135 int ret;
6136
6137 if (!wl->ops || !wl->ptable)
6138 return -EINVAL;
6139
6140 wl->dev = &pdev->dev;
6141 wl->pdev = pdev;
6142 platform_set_drvdata(pdev, wl);
6143
6144 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
6145 WL12XX_NVS_NAME, &pdev->dev, GFP_KERNEL,
6146 wl, wlcore_nvs_cb);
6147 if (ret < 0) {
6148 wl1271_error("request_firmware_nowait failed: %d", ret);
6149 complete_all(&wl->nvs_loading_complete);
6150 }
6151
Felipe Balbia390e852011-10-06 10:07:44 +03006152 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03006153}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02006154EXPORT_SYMBOL_GPL(wlcore_probe);
Felipe Balbice2a2172011-10-05 14:12:55 +03006155
Bill Pembertonb74324d2012-12-03 09:56:42 -05006156int wlcore_remove(struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03006157{
Felipe Balbia390e852011-10-06 10:07:44 +03006158 struct wl1271 *wl = platform_get_drvdata(pdev);
6159
Ido Yariv6f8d6b22012-09-02 01:32:47 +03006160 wait_for_completion(&wl->nvs_loading_complete);
6161 if (!wl->initialized)
6162 return 0;
6163
Felipe Balbia390e852011-10-06 10:07:44 +03006164 if (wl->irq_wake_enabled) {
6165 device_init_wakeup(wl->dev, 0);
6166 disable_irq_wake(wl->irq);
6167 }
6168 wl1271_unregister_hw(wl);
6169 free_irq(wl->irq, wl);
Luciano Coelhoffeb5012011-11-21 18:55:51 +02006170 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03006171
Felipe Balbice2a2172011-10-05 14:12:55 +03006172 return 0;
6173}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02006174EXPORT_SYMBOL_GPL(wlcore_remove);
Felipe Balbice2a2172011-10-05 14:12:55 +03006175
Guy Eilam491bbd62011-01-12 10:33:29 +01006176u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02006177EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01006178module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02006179MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
6180
Ido Yariv95dac04f2011-06-06 14:57:06 +03006181module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02006182MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03006183 "FW logger options: continuous, ondemand, dbgpins or disable");
6184
Yair Shapira72303412012-11-26 18:05:50 +02006185module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
Eliad Peller2a5bff02011-08-25 18:10:59 +03006186MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
6187
Yair Shapira72303412012-11-26 18:05:50 +02006188module_param(no_recovery, int, S_IRUSR | S_IWUSR);
Arik Nemtsov34785be2011-12-08 13:06:45 +02006189MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
6190
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02006191MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02006192MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02006193MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Tim Gardner0635ad42012-08-29 13:09:33 -06006194MODULE_FIRMWARE(WL12XX_NVS_NAME);