blob: 600ed7bc38db3bbbf1b78e176f1fcc0a1d4ab2d1 [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 Coelho33cab572013-05-04 02:46:38 +030042#include "sysfs.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030043
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020044#define WL1271_BOOT_RETRIES 3
45
Ido Yariv95dac04f2011-06-06 14:57:06 +030046static char *fwlog_param;
Yair Shapira72303412012-11-26 18:05:50 +020047static int bug_on_recovery = -1;
48static int no_recovery = -1;
Ido Yariv95dac04f2011-06-06 14:57:06 +030049
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030050static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +020051 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030052 bool reset_tx_queues);
Ido Yarivc24ec832012-06-26 21:08:58 +030053static void wlcore_op_stop_locked(struct wl1271 *wl);
Eliad Peller170d0e62011-10-05 11:56:06 +020054static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +020055
Luciano Coelho8f6ac532013-05-04 01:06:11 +030056static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pelleref4b29e2011-06-06 13:03:12 +030057{
58 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +020059
Eliad Peller9fd6f212012-03-04 10:55:48 +020060 if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
61 return -EINVAL;
62
63 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030064 return 0;
65
Eliad Peller8181aec2011-10-10 10:13:04 +020066 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030067 return 0;
68
Eliad Pellerd50529c2012-11-22 18:06:20 +020069 ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +030070 if (ret < 0)
71 return ret;
72
73 wl1271_info("Association completed.");
74 return 0;
75}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +030076
Luis R. Rodriguez0c0280b2013-01-11 18:39:36 +000077static void wl1271_reg_notify(struct wiphy *wiphy,
78 struct regulatory_request *request)
Luciano Coelho573c67c2010-11-26 13:44:59 +020079{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010080 struct ieee80211_supported_band *band;
81 struct ieee80211_channel *ch;
82 int i;
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +020083 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
84 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010085
86 band = wiphy->bands[IEEE80211_BAND_5GHZ];
87 for (i = 0; i < band->n_channels; i++) {
88 ch = &band->channels[i];
89 if (ch->flags & IEEE80211_CHAN_DISABLED)
90 continue;
91
92 if (ch->flags & IEEE80211_CHAN_RADAR)
93 ch->flags |= IEEE80211_CHAN_NO_IBSS |
94 IEEE80211_CHAN_PASSIVE_SCAN;
95
96 }
97
Arik Nemtsov75592be2013-03-12 17:19:45 +020098 wlcore_regdomain_config(wl);
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010099}
100
Eliad Peller9eb599e2011-10-10 10:12:59 +0200101static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
102 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300103{
104 int ret = 0;
105
106 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200107 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300108 if (ret < 0)
109 goto out;
110
111 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200112 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300113 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200114 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300115out:
116 return ret;
117}
118
119/*
120 * this function is being called when the rx_streaming interval
121 * has beed changed or rx_streaming should be disabled
122 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200123int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300124{
125 int ret = 0;
126 int period = wl->conf.rx_streaming.interval;
127
128 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200129 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300130 goto out;
131
132 /* reconfigure/disable according to new streaming_period */
133 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200134 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300135 (wl->conf.rx_streaming.always ||
136 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200137 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300138 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200139 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300140 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200141 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300142 }
143out:
144 return ret;
145}
146
147static void wl1271_rx_streaming_enable_work(struct work_struct *work)
148{
149 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200150 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
151 rx_streaming_enable_work);
152 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300153
154 mutex_lock(&wl->mutex);
155
Eliad Peller0744bdb2011-10-10 10:13:05 +0200156 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200157 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300158 (!wl->conf.rx_streaming.always &&
159 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
160 goto out;
161
162 if (!wl->conf.rx_streaming.interval)
163 goto out;
164
165 ret = wl1271_ps_elp_wakeup(wl);
166 if (ret < 0)
167 goto out;
168
Eliad Peller9eb599e2011-10-10 10:12:59 +0200169 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300170 if (ret < 0)
171 goto out_sleep;
172
173 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200174 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300175 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
176
177out_sleep:
178 wl1271_ps_elp_sleep(wl);
179out:
180 mutex_unlock(&wl->mutex);
181}
182
183static void wl1271_rx_streaming_disable_work(struct work_struct *work)
184{
185 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200186 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
187 rx_streaming_disable_work);
188 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300189
190 mutex_lock(&wl->mutex);
191
Eliad Peller0744bdb2011-10-10 10:13:05 +0200192 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300193 goto out;
194
195 ret = wl1271_ps_elp_wakeup(wl);
196 if (ret < 0)
197 goto out;
198
Eliad Peller9eb599e2011-10-10 10:12:59 +0200199 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300200 if (ret)
201 goto out_sleep;
202
203out_sleep:
204 wl1271_ps_elp_sleep(wl);
205out:
206 mutex_unlock(&wl->mutex);
207}
208
209static void wl1271_rx_streaming_timer(unsigned long data)
210{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200211 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
212 struct wl1271 *wl = wlvif->wl;
213 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300214}
215
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200216/* wl->mutex must be taken */
217void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
218{
219 /* if the watchdog is not armed, don't do anything */
220 if (wl->tx_allocated_blocks == 0)
221 return;
222
223 cancel_delayed_work(&wl->tx_watchdog_work);
224 ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work,
225 msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
226}
227
228static void wl12xx_tx_watchdog_work(struct work_struct *work)
229{
230 struct delayed_work *dwork;
231 struct wl1271 *wl;
232
233 dwork = container_of(work, struct delayed_work, work);
234 wl = container_of(dwork, struct wl1271, tx_watchdog_work);
235
236 mutex_lock(&wl->mutex);
237
Ido Yariv4cc53382012-07-24 19:18:49 +0300238 if (unlikely(wl->state != WLCORE_STATE_ON))
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200239 goto out;
240
241 /* Tx went out in the meantime - everything is ok */
242 if (unlikely(wl->tx_allocated_blocks == 0))
243 goto out;
244
245 /*
246 * if a ROC is in progress, we might not have any Tx for a long
247 * time (e.g. pending Tx on the non-ROC channels)
248 */
249 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
250 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC",
251 wl->conf.tx.tx_watchdog_timeout);
252 wl12xx_rearm_tx_watchdog_locked(wl);
253 goto out;
254 }
255
256 /*
257 * if a scan is in progress, we might not have any Tx for a long
258 * time
259 */
260 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
261 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan",
262 wl->conf.tx.tx_watchdog_timeout);
263 wl12xx_rearm_tx_watchdog_locked(wl);
264 goto out;
265 }
266
267 /*
268 * AP might cache a frame for a long time for a sleeping station,
269 * so rearm the timer if there's an AP interface with stations. If
270 * Tx is genuinely stuck we will most hopefully discover it when all
271 * stations are removed due to inactivity.
272 */
273 if (wl->active_sta_count) {
274 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has "
275 " %d stations",
276 wl->conf.tx.tx_watchdog_timeout,
277 wl->active_sta_count);
278 wl12xx_rearm_tx_watchdog_locked(wl);
279 goto out;
280 }
281
282 wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery",
283 wl->conf.tx.tx_watchdog_timeout);
284 wl12xx_queue_recovery_work(wl);
285
286out:
287 mutex_unlock(&wl->mutex);
288}
289
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200290static void wlcore_adjust_conf(struct wl1271 *wl)
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300291{
Ido Yariv95dac04f2011-06-06 14:57:06 +0300292 /* Adjust settings according to optional module parameters */
Yair Shapira72303412012-11-26 18:05:50 +0200293
Ido Yariv95dac04f2011-06-06 14:57:06 +0300294 if (fwlog_param) {
295 if (!strcmp(fwlog_param, "continuous")) {
296 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
297 } else if (!strcmp(fwlog_param, "ondemand")) {
298 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
299 } else if (!strcmp(fwlog_param, "dbgpins")) {
300 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
301 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
302 } else if (!strcmp(fwlog_param, "disable")) {
303 wl->conf.fwlog.mem_blocks = 0;
304 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
305 } else {
306 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
307 }
308 }
Yair Shapira72303412012-11-26 18:05:50 +0200309
310 if (bug_on_recovery != -1)
311 wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery;
312
313 if (no_recovery != -1)
314 wl->conf.recovery.no_recovery = (u8) no_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300315}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300316
Eliad Peller6e8cd332011-10-10 10:13:13 +0200317static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
318 struct wl12xx_vif *wlvif,
319 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200320{
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200321 bool fw_ps;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200322
Arik Nemtsovb622d992011-02-23 00:22:31 +0200323 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
324
325 /*
326 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300327 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200328 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300329 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200330 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200331
Arik Nemtsovda032092011-08-25 12:43:15 +0300332 /*
333 * Start high-level PS if the STA is asleep with enough blocks in FW.
Arik Nemtsov9a100962012-11-28 11:42:42 +0200334 * Make an exception if this is the only connected link. In this
335 * case FW-memory congestion is less of a problem.
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200336 * Note that a single connected STA means 3 active links, since we must
337 * account for the global and broadcast AP links. The "fw_ps" check
338 * assures us the third link is a STA connected to the AP. Otherwise
339 * the FW would not set the PSM bit.
Arik Nemtsovda032092011-08-25 12:43:15 +0300340 */
Arik Nemtsov37c68ea2013-03-12 17:19:36 +0200341 else if (wl->active_link_count > 3 && fw_ps &&
342 tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200343 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200344}
345
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300346static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200347 struct wl12xx_vif *wlvif,
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300348 struct wl_fw_status_2 *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200349{
350 u32 cur_fw_ps_map;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200351 u8 hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200352
353 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
354 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
355 wl1271_debug(DEBUG_PSM,
356 "link ps prev 0x%x cur 0x%x changed 0x%x",
357 wl->ap_fw_ps_map, cur_fw_ps_map,
358 wl->ap_fw_ps_map ^ cur_fw_ps_map);
359
360 wl->ap_fw_ps_map = cur_fw_ps_map;
361 }
362
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200363 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200364 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200365 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200366}
367
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300368static int wlcore_fw_status(struct wl1271 *wl,
369 struct wl_fw_status_1 *status_1,
370 struct wl_fw_status_2 *status_2)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300371{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200372 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200373 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200374 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300375 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300376 int i;
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200377 size_t status_len;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300378 int ret;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200379 struct wl1271_link *lnk;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300380
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300381 status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
382 sizeof(*status_2) + wl->fw_status_priv_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300383
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300384 ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
385 status_len, false);
386 if (ret < 0)
387 return ret;
Shahar Levi13b107d2011-03-06 16:32:12 +0200388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300389 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
390 "drv_rx_counter = %d, tx_results_counter = %d)",
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300391 status_1->intr,
392 status_1->fw_rx_counter,
393 status_1->drv_rx_counter,
394 status_1->tx_results_counter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300395
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300396 for (i = 0; i < NUM_TX_QUEUES; i++) {
397 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300398 wl->tx_allocated_pkts[i] -=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300399 (status_2->counters.tx_released_pkts[i] -
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300400 wl->tx_pkts_freed[i]) & 0xff;
401
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300402 wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300403 }
404
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200405
406 for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200407 u8 diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200408 lnk = &wl->links[i];
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200409
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200410 /* prevent wrap-around in freed-packets counter */
411 diff = (status_2->counters.tx_lnk_free_pkts[i] -
412 lnk->prev_freed_pkts) & 0xff;
413
414 if (diff == 0)
415 continue;
416
417 lnk->allocated_pkts -= diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200418 lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
Arik Nemtsov93d5d102013-03-12 17:19:38 +0200419
420 /* accumulate the prev_freed_pkts counter */
421 lnk->total_freed_pkts += diff;
Arik Nemtsov9ebcb232012-11-27 08:44:59 +0200422 }
423
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300424 /* prevent wrap-around in total blocks counter */
425 if (likely(wl->tx_blocks_freed <=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300426 le32_to_cpu(status_2->total_released_blks)))
427 freed_blocks = le32_to_cpu(status_2->total_released_blks) -
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300428 wl->tx_blocks_freed;
429 else
430 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300431 le32_to_cpu(status_2->total_released_blks);
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300432
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300433 wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200434
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300435 wl->tx_allocated_blocks -= freed_blocks;
436
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200437 /*
438 * If the FW freed some blocks:
439 * If we still have allocated blocks - re-arm the timer, Tx is
440 * not stuck. Otherwise, cancel the timer (no Tx currently).
441 */
442 if (freed_blocks) {
443 if (wl->tx_allocated_blocks)
444 wl12xx_rearm_tx_watchdog_locked(wl);
445 else
446 cancel_delayed_work(&wl->tx_watchdog_work);
447 }
448
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300449 avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200450
Eliad Peller4d56ad92011-08-14 13:17:05 +0300451 /*
452 * The FW might change the total number of TX memblocks before
453 * we get a notification about blocks being released. Thus, the
454 * available blocks calculation might yield a temporary result
455 * which is lower than the actual available blocks. Keeping in
456 * mind that only blocks that were allocated can be moved from
457 * TX to RX, tx_blocks_available should never decrease here.
458 */
459 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
460 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
Ido Yariva5225502010-10-12 14:49:10 +0200462 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200463 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200464 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
Eliad Peller4d56ad92011-08-14 13:17:05 +0300466 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200467 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300468 wl12xx_irq_update_links_status(wl, wlvif, status_2);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200469 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300470
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300471 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200472 getnstimeofday(&ts);
473 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300474 (s64)le32_to_cpu(status_2->fw_localtime);
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300475
Arik Nemtsov0e810472012-11-27 08:45:00 +0200476 wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
477
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300478 return 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300479}
480
Ido Yariva6208652011-03-01 15:14:41 +0200481static void wl1271_flush_deferred_work(struct wl1271 *wl)
482{
483 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200484
Ido Yariva6208652011-03-01 15:14:41 +0200485 /* Pass all received frames to the network stack */
486 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
487 ieee80211_rx_ni(wl->hw, skb);
488
489 /* Return sent skbs to the network stack */
490 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300491 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200492}
493
494static void wl1271_netstack_work(struct work_struct *work)
495{
496 struct wl1271 *wl =
497 container_of(work, struct wl1271, netstack_work);
498
499 do {
500 wl1271_flush_deferred_work(wl);
501 } while (skb_queue_len(&wl->deferred_rx_queue));
502}
503
504#define WL1271_IRQ_MAX_LOOPS 256
505
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300506static int wlcore_irq_locked(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300507{
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300508 int ret = 0;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300509 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200510 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200511 bool done = false;
512 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200513 unsigned long flags;
514
Ido Yariv341b7cd2011-03-31 10:07:01 +0200515 /*
516 * In case edge triggered interrupt must be used, we cannot iterate
517 * more than once without introducing race conditions with the hardirq.
518 */
519 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
520 loopcount = 1;
521
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300522 wl1271_debug(DEBUG_IRQ, "IRQ work");
523
Ido Yariv4cc53382012-07-24 19:18:49 +0300524 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525 goto out;
526
Ido Yariva6208652011-03-01 15:14:41 +0200527 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528 if (ret < 0)
529 goto out;
530
Ido Yariva6208652011-03-01 15:14:41 +0200531 while (!done && loopcount--) {
532 /*
533 * In order to avoid a race with the hardirq, clear the flag
534 * before acknowledging the chip. Since the mutex is held,
535 * wl1271_ps_elp_wakeup cannot be called concurrently.
536 */
537 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
538 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200539
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300540 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300541 if (ret < 0)
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300542 goto out;
Arik Nemtsov53d67a52011-12-12 11:32:37 +0200543
544 wlcore_hw_tx_immediate_compl(wl);
545
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300546 intr = le32_to_cpu(wl->fw_status_1->intr);
Ido Reisf5755fe2012-04-23 17:35:25 +0300547 intr &= WLCORE_ALL_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200548 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200549 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200550 continue;
551 }
552
Eliad Pellerccc83b02010-10-27 14:09:57 +0200553 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
Ido Reisf5755fe2012-04-23 17:35:25 +0300554 wl1271_error("HW watchdog interrupt received! starting recovery.");
555 wl->watchdog_recovery = true;
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300556 ret = -EIO;
Ido Reisf5755fe2012-04-23 17:35:25 +0300557
558 /* restarting the chip. ignore any other interrupt. */
559 goto out;
560 }
561
562 if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
563 wl1271_error("SW watchdog interrupt received! "
Eliad Pellerccc83b02010-10-27 14:09:57 +0200564 "starting recovery.");
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300565 wl->watchdog_recovery = true;
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300566 ret = -EIO;
Eliad Pellerccc83b02010-10-27 14:09:57 +0200567
568 /* restarting the chip. ignore any other interrupt. */
569 goto out;
570 }
571
Ido Yariva6208652011-03-01 15:14:41 +0200572 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
574
Ido Yariv045b9b52012-06-18 12:31:16 +0300575 ret = wlcore_rx(wl, wl->fw_status_1);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300576 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300577 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200578
Ido Yariva5225502010-10-12 14:49:10 +0200579 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200580 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200581 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300582 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200583 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200584 /*
585 * In order to avoid starvation of the TX path,
586 * call the work function directly.
587 */
Ido Yariveb96f842012-06-18 13:21:55 +0300588 ret = wlcore_tx_work_locked(wl);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300589 if (ret < 0)
Ido Yariveb96f842012-06-18 13:21:55 +0300590 goto out;
Ido Yarivb07d4032011-03-01 15:14:43 +0200591 } else {
592 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200593 }
594
Ido Yariv8aad2462011-03-01 15:14:38 +0200595 /* check for tx results */
Ido Yariv045b9b52012-06-18 12:31:16 +0300596 ret = wlcore_hw_tx_delayed_compl(wl);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300597 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300598 goto out;
Ido Yariva6208652011-03-01 15:14:41 +0200599
600 /* Make sure the deferred queues don't get too long */
601 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
602 skb_queue_len(&wl->deferred_rx_queue);
603 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
604 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 }
606
607 if (intr & WL1271_ACX_INTR_EVENT_A) {
608 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Ido Yariv045b9b52012-06-18 12:31:16 +0300609 ret = wl1271_event_handle(wl, 0);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300610 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300611 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200612 }
613
614 if (intr & WL1271_ACX_INTR_EVENT_B) {
615 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Ido Yariv045b9b52012-06-18 12:31:16 +0300616 ret = wl1271_event_handle(wl, 1);
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300617 if (ret < 0)
Ido Yariv045b9b52012-06-18 12:31:16 +0300618 goto out;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200619 }
620
621 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
622 wl1271_debug(DEBUG_IRQ,
623 "WL1271_ACX_INTR_INIT_COMPLETE");
624
625 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
626 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627 }
628
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629 wl1271_ps_elp_sleep(wl);
630
631out:
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300632 return ret;
633}
634
635static irqreturn_t wlcore_irq(int irq, void *cookie)
636{
637 int ret;
638 unsigned long flags;
639 struct wl1271 *wl = cookie;
640
Luciano Coelho97236a02013-03-08 09:41:53 +0200641 /* complete the ELP completion */
642 spin_lock_irqsave(&wl->wl_lock, flags);
643 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
644 if (wl->elp_compl) {
645 complete(wl->elp_compl);
646 wl->elp_compl = NULL;
647 }
648
649 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
650 /* don't enqueue a work right now. mark it as pending */
651 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
652 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
653 disable_irq_nosync(wl->irq);
654 pm_wakeup_event(wl->dev, 0);
655 spin_unlock_irqrestore(&wl->wl_lock, flags);
656 return IRQ_HANDLED;
657 }
658 spin_unlock_irqrestore(&wl->wl_lock, flags);
659
Arik Nemtsovb5b45b32012-06-21 18:10:51 +0300660 /* TX might be handled here, avoid redundant work */
661 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
662 cancel_work_sync(&wl->tx_work);
663
664 mutex_lock(&wl->mutex);
665
666 ret = wlcore_irq_locked(wl);
667 if (ret)
668 wl12xx_queue_recovery_work(wl);
669
Ido Yarivb07d4032011-03-01 15:14:43 +0200670 spin_lock_irqsave(&wl->wl_lock, flags);
671 /* In case TX was not handled here, queue TX work */
672 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
673 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300674 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200675 ieee80211_queue_work(wl->hw, &wl->tx_work);
676 spin_unlock_irqrestore(&wl->wl_lock, flags);
677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200679
680 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681}
682
Eliad Peller4549d092012-02-06 13:07:52 +0200683struct vif_counter_data {
684 u8 counter;
685
686 struct ieee80211_vif *cur_vif;
687 bool cur_vif_running;
688};
689
690static void wl12xx_vif_count_iter(void *data, u8 *mac,
691 struct ieee80211_vif *vif)
692{
693 struct vif_counter_data *counter = data;
694
695 counter->counter++;
696 if (counter->cur_vif == vif)
697 counter->cur_vif_running = true;
698}
699
700/* caller must not hold wl->mutex, as it might deadlock */
701static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
702 struct ieee80211_vif *cur_vif,
703 struct vif_counter_data *data)
704{
705 memset(data, 0, sizeof(*data));
706 data->cur_vif = cur_vif;
707
Johannes Berg8b2c9822012-11-06 20:23:30 +0100708 ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
Eliad Peller4549d092012-02-06 13:07:52 +0200709 wl12xx_vif_count_iter, data);
710}
711
Eliad Peller3fcdab72012-02-06 12:47:54 +0200712static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713{
714 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200715 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200716 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717 int ret;
718
Eliad Peller3fcdab72012-02-06 12:47:54 +0200719 if (plt) {
720 fw_type = WL12XX_FW_TYPE_PLT;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200721 fw_name = wl->plt_fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200722 } else {
Eliad Peller4549d092012-02-06 13:07:52 +0200723 /*
724 * we can't call wl12xx_get_vif_count() here because
725 * wl->mutex is taken, so use the cached last_vif_count value
726 */
Eliad Peller9b1a0a72012-07-25 14:22:21 +0300727 if (wl->last_vif_count > 1 && wl->mr_fw_name) {
Eliad Peller4549d092012-02-06 13:07:52 +0200728 fw_type = WL12XX_FW_TYPE_MULTI;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200729 fw_name = wl->mr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200730 } else {
731 fw_type = WL12XX_FW_TYPE_NORMAL;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200732 fw_name = wl->sr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200733 }
Eliad Peller3fcdab72012-02-06 12:47:54 +0200734 }
735
736 if (wl->fw_type == fw_type)
737 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200738
739 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
740
Felipe Balbia390e852011-10-06 10:07:44 +0300741 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742
743 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100744 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745 return ret;
746 }
747
748 if (fw->size % 4) {
749 wl1271_error("firmware size is not multiple of 32 bits: %zu",
750 fw->size);
751 ret = -EILSEQ;
752 goto out;
753 }
754
Arik Nemtsov166d5042010-10-16 21:44:57 +0200755 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +0200756 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300758 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
760 if (!wl->fw) {
761 wl1271_error("could not allocate memory for the firmware");
762 ret = -ENOMEM;
763 goto out;
764 }
765
766 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767 ret = 0;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200768 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769out:
770 release_firmware(fw);
771
772 return ret;
773}
774
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300775void wl12xx_queue_recovery_work(struct wl1271 *wl)
776{
Eyal Shapira680c6052012-06-26 10:41:17 +0300777 WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
778
Ido Yarivb666bb72012-05-21 01:10:11 +0300779 /* Avoid a recursive recovery */
Ido Yariv792a58a2012-08-15 15:09:30 +0300780 if (wl->state == WLCORE_STATE_ON) {
Ido Yariv4cc53382012-07-24 19:18:49 +0300781 wl->state = WLCORE_STATE_RESTARTING;
Ido Yariv792a58a2012-08-15 15:09:30 +0300782 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
Ido Yarivb666bb72012-05-21 01:10:11 +0300783 wlcore_disable_interrupts_nosync(wl);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300784 ieee80211_queue_work(wl->hw, &wl->recovery_work);
Ido Yarivb666bb72012-05-21 01:10:11 +0300785 }
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300786}
787
Ido Yariv95dac04f2011-06-06 14:57:06 +0300788size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
789{
790 size_t len = 0;
791
792 /* The FW log is a length-value list, find where the log end */
793 while (len < maxlen) {
794 if (memblock[len] == 0)
795 break;
796 if (len + memblock[len] + 1 > maxlen)
797 break;
798 len += memblock[len] + 1;
799 }
800
801 /* Make sure we have enough room */
802 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
803
804 /* Fill the FW log file, consumed by the sysfs fwlog entry */
805 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
806 wl->fwlog_size += len;
807
808 return len;
809}
810
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300811#define WLCORE_FW_LOG_END 0x2000000
812
Ido Yariv95dac04f2011-06-06 14:57:06 +0300813static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
814{
815 u32 addr;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300816 u32 offset;
817 u32 end_of_log;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300818 u8 *block;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300819 int ret;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300820
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200821 if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
Ido Yariv95dac04f2011-06-06 14:57:06 +0300822 (wl->conf.fwlog.mem_blocks == 0))
823 return;
824
825 wl1271_info("Reading FW panic log");
826
827 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
828 if (!block)
829 return;
830
831 /*
832 * Make sure the chip is awake and the logger isn't active.
Eliad Peller847cbeb2012-11-26 18:05:42 +0200833 * Do not send a stop fwlog command if the fw is hanged or if
834 * dbgpins are used (due to some fw bug).
Ido Yariv95dac04f2011-06-06 14:57:06 +0300835 */
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300836 if (wl1271_ps_elp_wakeup(wl))
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300837 goto out;
Eliad Peller847cbeb2012-11-26 18:05:42 +0200838 if (!wl->watchdog_recovery &&
839 wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300840 wl12xx_cmd_stop_fwlog(wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +0300841
842 /* Read the first memory block address */
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300843 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
844 if (ret < 0)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300845 goto out;
846
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300847 addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
848 if (!addr)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300849 goto out;
850
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300851 if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
852 offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
853 end_of_log = WLCORE_FW_LOG_END;
854 } else {
855 offset = sizeof(addr);
856 end_of_log = addr;
857 }
858
Ido Yariv95dac04f2011-06-06 14:57:06 +0300859 /* Traverse the memory blocks linked list */
Ido Yariv95dac04f2011-06-06 14:57:06 +0300860 do {
861 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
Ido Yariv2b800402012-06-18 18:15:50 +0300862 ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
863 false);
864 if (ret < 0)
865 goto out;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300866
867 /*
868 * Memory blocks are linked to one another. The first 4 bytes
869 * of each memory block hold the hardware address of the next
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300870 * one. The last memory block points to the first one in
871 * on demand mode and is equal to 0x2000000 in continuous mode.
Ido Yariv95dac04f2011-06-06 14:57:06 +0300872 */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300873 addr = le32_to_cpup((__le32 *)block);
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300874 if (!wl12xx_copy_fwlog(wl, block + offset,
875 WL12XX_HW_BLOCK_SIZE - offset))
Ido Yariv95dac04f2011-06-06 14:57:06 +0300876 break;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300877 } while (addr && (addr != end_of_log));
Ido Yariv95dac04f2011-06-06 14:57:06 +0300878
879 wake_up_interruptible(&wl->fwlog_waitq);
880
881out:
882 kfree(block);
883}
884
Ido Yariv61343232012-06-18 15:50:21 +0300885static void wlcore_print_recovery(struct wl1271 *wl)
886{
887 u32 pc = 0;
888 u32 hint_sts = 0;
889 int ret;
890
891 wl1271_info("Hardware recovery in progress. FW ver: %s",
892 wl->chip.fw_ver_str);
893
894 /* change partitions momentarily so we can read the FW pc */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300895 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
896 if (ret < 0)
897 return;
Ido Yariv61343232012-06-18 15:50:21 +0300898
899 ret = wlcore_read_reg(wl, REG_PC_ON_RECOVERY, &pc);
900 if (ret < 0)
901 return;
902
903 ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &hint_sts);
904 if (ret < 0)
905 return;
906
Luciano Coelhoc108c902012-11-26 18:05:49 +0200907 wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d",
908 pc, hint_sts, ++wl->recovery_count);
Ido Yariv61343232012-06-18 15:50:21 +0300909
910 wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
911}
912
913
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200914static void wl1271_recovery_work(struct work_struct *work)
915{
916 struct wl1271 *wl =
917 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +0200918 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +0200919 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200920
921 mutex_lock(&wl->mutex);
922
Ido Yariv4cc53382012-07-24 19:18:49 +0300923 if (wl->state == WLCORE_STATE_OFF || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +0200924 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200925
Arik Nemtsovaafec112012-06-25 22:26:19 +0300926 if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) {
927 wl12xx_read_fwlog_panic(wl);
928 wlcore_print_recovery(wl);
929 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200930
Yair Shapira72303412012-11-26 18:05:50 +0200931 BUG_ON(wl->conf.recovery.bug_on_recovery &&
Eliad Pellere9ba7152012-03-04 10:55:54 +0200932 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
Eliad Peller2a5bff02011-08-25 18:10:59 +0300933
Yair Shapira72303412012-11-26 18:05:50 +0200934 if (wl->conf.recovery.no_recovery) {
Arik Nemtsov34785be2011-12-08 13:06:45 +0200935 wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
Arik Nemtsov34785be2011-12-08 13:06:45 +0200936 goto out_unlock;
937 }
938
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300939 /* Prevent spurious TX during FW restart */
Arik Nemtsov66396112012-05-18 07:46:38 +0300940 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300941
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200942 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200943 while (!list_empty(&wl->wlvif_list)) {
944 wlvif = list_first_entry(&wl->wlvif_list,
945 struct wl12xx_vif, list);
946 vif = wl12xx_wlvif_to_vif(wlvif);
947 __wl1271_op_remove_interface(wl, vif, false);
948 }
Ido Yarivc24ec832012-06-26 21:08:58 +0300949
950 wlcore_op_stop_locked(wl);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300951
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200952 ieee80211_restart_hw(wl->hw);
953
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300954 /*
955 * Its safe to enable TX now - the queues are stopped after a request
956 * to restart the HW.
957 */
Arik Nemtsov66396112012-05-18 07:46:38 +0300958 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Ido Yarivc24ec832012-06-26 21:08:58 +0300959
Eliad Pellerf0277432011-10-10 10:13:14 +0200960out_unlock:
Arik Nemtsovb034fd62012-06-25 22:26:20 +0300961 wl->watchdog_recovery = false;
962 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200963 mutex_unlock(&wl->mutex);
964}
965
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300966static int wlcore_fw_wakeup(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967{
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300968 return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969}
970
971static int wl1271_setup(struct wl1271 *wl)
972{
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300973 wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
Luciano Coelho4f64a1e2012-05-10 12:14:00 +0300974 sizeof(*wl->fw_status_2) +
975 wl->fw_status_priv_len, GFP_KERNEL);
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300976 if (!wl->fw_status_1)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 return -ENOMEM;
978
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300979 wl->fw_status_2 = (struct wl_fw_status_2 *)
980 (((u8 *) wl->fw_status_1) +
981 WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
984 if (!wl->tx_res_if) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300985 kfree(wl->fw_status_1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986 return -ENOMEM;
987 }
988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 return 0;
990}
991
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200992static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200994 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200996 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200997 ret = wl1271_power_on(wl);
998 if (ret < 0)
999 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001001 wl1271_io_reset(wl);
1002 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001004 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
1005 if (ret < 0)
1006 goto fail;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
1008 /* ELP module wake up */
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001009 ret = wlcore_fw_wakeup(wl);
1010 if (ret < 0)
1011 goto fail;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001013out:
1014 return ret;
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001015
1016fail:
1017 wl1271_power_off(wl);
1018 return ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001019}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020
Eliad Peller3fcdab72012-02-06 12:47:54 +02001021static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001022{
1023 int ret = 0;
1024
1025 ret = wl12xx_set_power_on(wl);
1026 if (ret < 0)
1027 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001029 /*
1030 * For wl127x based devices we could use the default block
1031 * size (512 bytes), but due to a bug in the sdio driver, we
1032 * need to set it explicitly after the chip is powered on. To
1033 * simplify the code and since the performance impact is
1034 * negligible, we use the same block size for all different
1035 * chip types.
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +03001036 *
1037 * Check if the bus supports blocksize alignment and, if it
1038 * doesn't, make sure we don't have the quirk.
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001039 */
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +03001040 if (!wl1271_set_block_size(wl))
1041 wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001043 /* TODO: make sure the lower driver has set things up correctly */
1044
1045 ret = wl1271_setup(wl);
1046 if (ret < 0)
1047 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
Eliad Peller3fcdab72012-02-06 12:47:54 +02001049 ret = wl12xx_fetch_firmware(wl, plt);
1050 if (ret < 0)
1051 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053out:
1054 return ret;
1055}
1056
Yair Shapira7019c802012-07-11 18:48:04 +03001057int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001059 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001060 struct wiphy *wiphy = wl->hw->wiphy;
Yair Shapira7019c802012-07-11 18:48:04 +03001061
1062 static const char* const PLT_MODE[] = {
1063 "PLT_OFF",
1064 "PLT_ON",
1065 "PLT_FEM_DETECT"
1066 };
1067
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 int ret;
1069
1070 mutex_lock(&wl->mutex);
1071
1072 wl1271_notice("power up");
1073
Ido Yariv4cc53382012-07-24 19:18:49 +03001074 if (wl->state != WLCORE_STATE_OFF) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 wl1271_error("cannot go into PLT state because not "
1076 "in off state: %d", wl->state);
1077 ret = -EBUSY;
1078 goto out;
1079 }
1080
Yair Shapira7019c802012-07-11 18:48:04 +03001081 /* Indicate to lower levels that we are now in PLT mode */
1082 wl->plt = true;
1083 wl->plt_mode = plt_mode;
1084
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001085 while (retries) {
1086 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001087 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001088 if (ret < 0)
1089 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090
Luciano Coelhoc331b342012-05-10 12:13:49 +03001091 ret = wl->ops->plt_init(wl);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001092 if (ret < 0)
1093 goto power_off;
1094
Ido Yariv4cc53382012-07-24 19:18:49 +03001095 wl->state = WLCORE_STATE_ON;
Yair Shapira7019c802012-07-11 18:48:04 +03001096 wl1271_notice("firmware booted in PLT mode %s (%s)",
1097 PLT_MODE[plt_mode],
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001098 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001099
Gery Kahn6f07b722011-07-18 14:21:49 +03001100 /* update hw/fw version info in wiphy struct */
1101 wiphy->hw_version = wl->chip.id;
1102 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1103 sizeof(wiphy->fw_version));
1104
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105 goto out;
1106
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001107power_off:
1108 wl1271_power_off(wl);
1109 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
Yair Shapira7019c802012-07-11 18:48:04 +03001111 wl->plt = false;
1112 wl->plt_mode = PLT_OFF;
1113
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001114 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1115 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116out:
1117 mutex_unlock(&wl->mutex);
1118
1119 return ret;
1120}
1121
Ido Yarivf3df1332012-01-11 09:42:39 +02001122int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123{
1124 int ret = 0;
1125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126 wl1271_notice("power down");
1127
Ido Yariv46b0cc92012-01-11 09:42:41 +02001128 /*
1129 * Interrupts must be disabled before setting the state to OFF.
1130 * Otherwise, the interrupt handler might be called and exit without
1131 * reading the interrupt status.
1132 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001133 wlcore_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001134 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001135 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001136 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001137
1138 /*
1139 * This will not necessarily enable interrupts as interrupts
1140 * may have been disabled when op_stop was called. It will,
1141 * however, balance the above call to disable_interrupts().
1142 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001143 wlcore_enable_interrupts(wl);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001145 wl1271_error("cannot power down because not in PLT "
1146 "state: %d", wl->state);
1147 ret = -EBUSY;
1148 goto out;
1149 }
1150
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001151 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001152
Ido Yariva6208652011-03-01 15:14:41 +02001153 wl1271_flush_deferred_work(wl);
1154 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001155 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001156 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001157 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Ido Yariva4549692012-01-11 09:42:40 +02001158
1159 mutex_lock(&wl->mutex);
1160 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001161 wl->flags = 0;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001162 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Ido Yariv4cc53382012-07-24 19:18:49 +03001163 wl->state = WLCORE_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001164 wl->plt = false;
Yair Shapira7019c802012-07-11 18:48:04 +03001165 wl->plt_mode = PLT_OFF;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001166 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001167 mutex_unlock(&wl->mutex);
1168
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001169out:
1170 return ret;
1171}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001172
Thomas Huehn36323f82012-07-23 21:33:42 +02001173static void wl1271_op_tx(struct ieee80211_hw *hw,
1174 struct ieee80211_tx_control *control,
1175 struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176{
1177 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001178 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1179 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001180 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001181 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001182 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001183 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001184
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001185 if (!vif) {
1186 wl1271_debug(DEBUG_TX, "DROP skb with no vif");
1187 ieee80211_free_txskb(hw, skb);
1188 return;
1189 }
Eliad Peller0f168012011-10-11 13:52:25 +02001190
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001191 wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001192 mapping = skb_get_queue_mapping(skb);
1193 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001194
Thomas Huehn36323f82012-07-23 21:33:42 +02001195 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb, control->sta);
Ido Yarivb07d4032011-03-01 15:14:43 +02001196
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001197 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001198
Arik Nemtsov66396112012-05-18 07:46:38 +03001199 /*
1200 * drop the packet if the link is invalid or the queue is stopped
1201 * for any reason but watermark. Watermark is a "soft"-stop so we
1202 * allow these packets through.
1203 */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001204 if (hlid == WL12XX_INVALID_LINK_ID ||
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001205 (!test_bit(hlid, wlvif->links_map)) ||
Arik Nemtsovd6037d22012-11-28 11:42:44 +02001206 (wlcore_is_queue_stopped_locked(wl, wlvif, q) &&
1207 !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
Arik Nemtsov66396112012-05-18 07:46:38 +03001208 WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001209 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001210 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001211 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001212 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213
Eliad Peller8ccd16e2012-03-04 10:55:55 +02001214 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d",
1215 hlid, q, skb->len);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001216 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1217
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001218 wl->tx_queue_count[q]++;
Arik Nemtsovf4d02002012-11-28 11:42:33 +02001219 wlvif->tx_queue_count[q]++;
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001220
1221 /*
1222 * The workqueue is slow to process the tx_queue and we need stop
1223 * the queue here, otherwise the queue will get too long.
1224 */
Arik Nemtsov1c33db72012-11-30 00:48:03 +02001225 if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
Arik Nemtsovd6037d22012-11-28 11:42:44 +02001226 !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
Arik Nemtsov8cdc44a2012-06-25 22:26:17 +03001227 WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001228 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
Arik Nemtsov1c33db72012-11-30 00:48:03 +02001229 wlcore_stop_queue_locked(wl, wlvif, q,
Arik Nemtsov66396112012-05-18 07:46:38 +03001230 WLCORE_QUEUE_STOP_REASON_WATERMARK);
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001231 }
1232
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001233 /*
1234 * The chip specific setup must run before the first TX packet -
1235 * before that, the tx_work will not be initialized!
1236 */
1237
Ido Yarivb07d4032011-03-01 15:14:43 +02001238 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1239 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001240 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001241
Arik Nemtsov04216da2011-08-14 13:17:38 +03001242out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001243 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244}
1245
Shahar Leviae47c452011-03-06 16:32:14 +02001246int wl1271_tx_dummy_packet(struct wl1271 *wl)
1247{
Ido Yariv990f5de2011-03-31 10:06:59 +02001248 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001249 int q;
1250
1251 /* no need to queue a new dummy packet if one is already pending */
1252 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1253 return 0;
1254
1255 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001256
Ido Yariv990f5de2011-03-31 10:06:59 +02001257 spin_lock_irqsave(&wl->wl_lock, flags);
1258 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001259 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001260 spin_unlock_irqrestore(&wl->wl_lock, flags);
1261
1262 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1263 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Ido Yariveb96f842012-06-18 13:21:55 +03001264 return wlcore_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001265
1266 /*
1267 * If the FW TX is busy, TX work will be scheduled by the threaded
1268 * interrupt handler function
1269 */
1270 return 0;
1271}
1272
1273/*
1274 * The size of the dummy packet should be at least 1400 bytes. However, in
1275 * order to minimize the number of bus transactions, aligning it to 512 bytes
1276 * boundaries could be beneficial, performance wise
1277 */
1278#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1279
Luciano Coelhocf27d862011-04-01 21:08:23 +03001280static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001281{
1282 struct sk_buff *skb;
1283 struct ieee80211_hdr_3addr *hdr;
1284 unsigned int dummy_packet_size;
1285
1286 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1287 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1288
1289 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001290 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001291 wl1271_warning("Failed to allocate a dummy packet skb");
1292 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001293 }
1294
1295 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1296
1297 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1298 memset(hdr, 0, sizeof(*hdr));
1299 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001300 IEEE80211_STYPE_NULLFUNC |
1301 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001302
Ido Yariv990f5de2011-03-31 10:06:59 +02001303 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001304
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001305 /* Dummy packets require the TID to be management */
1306 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001307
1308 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001309 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001310 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001311
Ido Yariv990f5de2011-03-31 10:06:59 +02001312 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001313}
1314
Ido Yariv990f5de2011-03-31 10:06:59 +02001315
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001316#ifdef CONFIG_PM
Luciano Coelho22479972012-05-16 06:00:00 +03001317static int
1318wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001319{
1320 int num_fields = 0, in_field = 0, fields_size = 0;
1321 int i, pattern_len = 0;
1322
1323 if (!p->mask) {
1324 wl1271_warning("No mask in WoWLAN pattern");
1325 return -EINVAL;
1326 }
1327
1328 /*
1329 * The pattern is broken up into segments of bytes at different offsets
1330 * that need to be checked by the FW filter. Each segment is called
1331 * a field in the FW API. We verify that the total number of fields
1332 * required for this pattern won't exceed FW limits (8)
1333 * as well as the total fields buffer won't exceed the FW limit.
1334 * Note that if there's a pattern which crosses Ethernet/IP header
1335 * boundary a new field is required.
1336 */
1337 for (i = 0; i < p->pattern_len; i++) {
1338 if (test_bit(i, (unsigned long *)p->mask)) {
1339 if (!in_field) {
1340 in_field = 1;
1341 pattern_len = 1;
1342 } else {
1343 if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1344 num_fields++;
1345 fields_size += pattern_len +
1346 RX_FILTER_FIELD_OVERHEAD;
1347 pattern_len = 1;
1348 } else
1349 pattern_len++;
1350 }
1351 } else {
1352 if (in_field) {
1353 in_field = 0;
1354 fields_size += pattern_len +
1355 RX_FILTER_FIELD_OVERHEAD;
1356 num_fields++;
1357 }
1358 }
1359 }
1360
1361 if (in_field) {
1362 fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
1363 num_fields++;
1364 }
1365
1366 if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
1367 wl1271_warning("RX Filter too complex. Too many segments");
1368 return -EINVAL;
1369 }
1370
1371 if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
1372 wl1271_warning("RX filter pattern is too big");
1373 return -E2BIG;
1374 }
1375
1376 return 0;
1377}
1378
Eyal Shapiraa6eab0c2012-03-14 06:32:07 +02001379struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
1380{
1381 return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
1382}
1383
1384void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
1385{
1386 int i;
1387
1388 if (filter == NULL)
1389 return;
1390
1391 for (i = 0; i < filter->num_fields; i++)
1392 kfree(filter->fields[i].pattern);
1393
1394 kfree(filter);
1395}
1396
1397int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
1398 u16 offset, u8 flags,
1399 u8 *pattern, u8 len)
1400{
1401 struct wl12xx_rx_filter_field *field;
1402
1403 if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
1404 wl1271_warning("Max fields per RX filter. can't alloc another");
1405 return -EINVAL;
1406 }
1407
1408 field = &filter->fields[filter->num_fields];
1409
1410 field->pattern = kzalloc(len, GFP_KERNEL);
1411 if (!field->pattern) {
1412 wl1271_warning("Failed to allocate RX filter pattern");
1413 return -ENOMEM;
1414 }
1415
1416 filter->num_fields++;
1417
1418 field->offset = cpu_to_le16(offset);
1419 field->flags = flags;
1420 field->len = len;
1421 memcpy(field->pattern, pattern, len);
1422
1423 return 0;
1424}
1425
1426int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
1427{
1428 int i, fields_size = 0;
1429
1430 for (i = 0; i < filter->num_fields; i++)
1431 fields_size += filter->fields[i].len +
1432 sizeof(struct wl12xx_rx_filter_field) -
1433 sizeof(u8 *);
1434
1435 return fields_size;
1436}
1437
1438void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
1439 u8 *buf)
1440{
1441 int i;
1442 struct wl12xx_rx_filter_field *field;
1443
1444 for (i = 0; i < filter->num_fields; i++) {
1445 field = (struct wl12xx_rx_filter_field *)buf;
1446
1447 field->offset = filter->fields[i].offset;
1448 field->flags = filter->fields[i].flags;
1449 field->len = filter->fields[i].len;
1450
1451 memcpy(&field->pattern, filter->fields[i].pattern, field->len);
1452 buf += sizeof(struct wl12xx_rx_filter_field) -
1453 sizeof(u8 *) + field->len;
1454 }
1455}
1456
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001457/*
1458 * Allocates an RX filter returned through f
1459 * which needs to be freed using rx_filter_free()
1460 */
Luciano Coelho22479972012-05-16 06:00:00 +03001461static int wl1271_convert_wowlan_pattern_to_rx_filter(
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001462 struct cfg80211_wowlan_trig_pkt_pattern *p,
1463 struct wl12xx_rx_filter **f)
1464{
1465 int i, j, ret = 0;
1466 struct wl12xx_rx_filter *filter;
1467 u16 offset;
1468 u8 flags, len;
1469
1470 filter = wl1271_rx_filter_alloc();
1471 if (!filter) {
1472 wl1271_warning("Failed to alloc rx filter");
1473 ret = -ENOMEM;
1474 goto err;
1475 }
1476
1477 i = 0;
1478 while (i < p->pattern_len) {
1479 if (!test_bit(i, (unsigned long *)p->mask)) {
1480 i++;
1481 continue;
1482 }
1483
1484 for (j = i; j < p->pattern_len; j++) {
1485 if (!test_bit(j, (unsigned long *)p->mask))
1486 break;
1487
1488 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
1489 j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
1490 break;
1491 }
1492
1493 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1494 offset = i;
1495 flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
1496 } else {
1497 offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
1498 flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
1499 }
1500
1501 len = j - i;
1502
1503 ret = wl1271_rx_filter_alloc_field(filter,
1504 offset,
1505 flags,
1506 &p->pattern[i], len);
1507 if (ret)
1508 goto err;
1509
1510 i = j;
1511 }
1512
1513 filter->action = FILTER_SIGNAL;
1514
1515 *f = filter;
1516 return 0;
1517
1518err:
1519 wl1271_rx_filter_free(filter);
1520 *f = NULL;
1521
1522 return ret;
1523}
1524
1525static int wl1271_configure_wowlan(struct wl1271 *wl,
1526 struct cfg80211_wowlan *wow)
1527{
1528 int i, ret;
1529
1530 if (!wow || wow->any || !wow->n_patterns) {
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001531 ret = wl1271_acx_default_rx_filter_enable(wl, 0,
1532 FILTER_SIGNAL);
1533 if (ret)
1534 goto out;
1535
1536 ret = wl1271_rx_filter_clear_all(wl);
1537 if (ret)
1538 goto out;
1539
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001540 return 0;
1541 }
1542
1543 if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
1544 return -EINVAL;
1545
1546 /* Validate all incoming patterns before clearing current FW state */
1547 for (i = 0; i < wow->n_patterns; i++) {
1548 ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
1549 if (ret) {
1550 wl1271_warning("Bad wowlan pattern %d", i);
1551 return ret;
1552 }
1553 }
1554
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001555 ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1556 if (ret)
1557 goto out;
1558
1559 ret = wl1271_rx_filter_clear_all(wl);
1560 if (ret)
1561 goto out;
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001562
1563 /* Translate WoWLAN patterns into filters */
1564 for (i = 0; i < wow->n_patterns; i++) {
1565 struct cfg80211_wowlan_trig_pkt_pattern *p;
1566 struct wl12xx_rx_filter *filter = NULL;
1567
1568 p = &wow->patterns[i];
1569
1570 ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
1571 if (ret) {
1572 wl1271_warning("Failed to create an RX filter from "
1573 "wowlan pattern %d", i);
1574 goto out;
1575 }
1576
1577 ret = wl1271_rx_filter_enable(wl, i, 1, filter);
1578
1579 wl1271_rx_filter_free(filter);
1580 if (ret)
1581 goto out;
1582 }
1583
1584 ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
1585
1586out:
1587 return ret;
1588}
1589
Eyal Shapiradae728f2012-02-02 12:03:39 +02001590static int wl1271_configure_suspend_sta(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001591 struct wl12xx_vif *wlvif,
1592 struct cfg80211_wowlan *wow)
Eyal Shapiradae728f2012-02-02 12:03:39 +02001593{
1594 int ret = 0;
1595
Eyal Shapiradae728f2012-02-02 12:03:39 +02001596 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001597 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001598
1599 ret = wl1271_ps_elp_wakeup(wl);
1600 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001601 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001602
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001603 ret = wl1271_configure_wowlan(wl, wow);
1604 if (ret < 0)
1605 goto out_sleep;
1606
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001607 if ((wl->conf.conn.suspend_wake_up_event ==
1608 wl->conf.conn.wake_up_event) &&
1609 (wl->conf.conn.suspend_listen_interval ==
1610 wl->conf.conn.listen_interval))
1611 goto out_sleep;
1612
Eyal Shapiradae728f2012-02-02 12:03:39 +02001613 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1614 wl->conf.conn.suspend_wake_up_event,
1615 wl->conf.conn.suspend_listen_interval);
1616
1617 if (ret < 0)
1618 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1619
Arik Nemtsovc439a1c2012-06-21 18:10:50 +03001620out_sleep:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001621 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001622out:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001623 return ret;
1624
1625}
Eliad Peller94390642011-05-13 11:57:13 +03001626
Eliad Peller0603d892011-10-05 11:55:51 +02001627static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1628 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001629{
Eliad Pellere85d1622011-06-27 13:06:43 +03001630 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001631
Eliad Peller53d40d02011-10-10 10:13:02 +02001632 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001633 goto out;
Eliad Pellere85d1622011-06-27 13:06:43 +03001634
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001637 goto out;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001638
Eliad Peller0603d892011-10-05 11:55:51 +02001639 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640
1641 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001642out:
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001643 return ret;
1644
1645}
1646
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001647static int wl1271_configure_suspend(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001648 struct wl12xx_vif *wlvif,
1649 struct cfg80211_wowlan *wow)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001651 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001652 return wl1271_configure_suspend_sta(wl, wlvif, wow);
Eliad Peller536129c2011-10-05 11:55:45 +02001653 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001654 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001655 return 0;
1656}
1657
Luciano Coelho8f6ac532013-05-04 01:06:11 +03001658static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001659{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001660 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001661 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001662 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663
Eyal Shapiradae728f2012-02-02 12:03:39 +02001664 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001665 return;
1666
Eliad Pellerd49524d2012-08-01 18:44:22 +03001667 if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1668 return;
1669
Eliad Peller94390642011-05-13 11:57:13 +03001670 ret = wl1271_ps_elp_wakeup(wl);
1671 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001672 return;
Eliad Peller94390642011-05-13 11:57:13 +03001673
Eyal Shapiradae728f2012-02-02 12:03:39 +02001674 if (is_sta) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001675 wl1271_configure_wowlan(wl, NULL);
1676
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001677 if ((wl->conf.conn.suspend_wake_up_event ==
1678 wl->conf.conn.wake_up_event) &&
1679 (wl->conf.conn.suspend_listen_interval ==
1680 wl->conf.conn.listen_interval))
1681 goto out_sleep;
1682
Eyal Shapiradae728f2012-02-02 12:03:39 +02001683 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1684 wl->conf.conn.wake_up_event,
1685 wl->conf.conn.listen_interval);
1686
1687 if (ret < 0)
1688 wl1271_error("resume: wake up conditions failed: %d",
1689 ret);
1690
1691 } else if (is_ap) {
1692 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1693 }
Eliad Peller94390642011-05-13 11:57:13 +03001694
Eyal Shapira11bc97e2012-08-02 07:15:19 +03001695out_sleep:
Eliad Peller94390642011-05-13 11:57:13 +03001696 wl1271_ps_elp_sleep(wl);
Eliad Peller94390642011-05-13 11:57:13 +03001697}
1698
Eliad Peller402e48612011-05-13 11:57:09 +03001699static int wl1271_op_suspend(struct ieee80211_hw *hw,
1700 struct cfg80211_wowlan *wow)
1701{
1702 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001703 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001704 int ret;
1705
Eliad Peller402e48612011-05-13 11:57:09 +03001706 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001707 WARN_ON(!wow);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001708
Arik Nemtsov96caded2012-06-21 18:10:47 +03001709 /* we want to perform the recovery before suspending */
1710 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1711 wl1271_warning("postponing suspend to perform recovery");
1712 return -EBUSY;
1713 }
1714
Arik Nemtsovb9239b62012-02-28 00:41:33 +02001715 wl1271_tx_flush(wl);
1716
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001717 mutex_lock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001718 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001719 wl12xx_for_each_wlvif(wl, wlvif) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001720 ret = wl1271_configure_suspend(wl, wlvif, wow);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001721 if (ret < 0) {
Dan Carpentercd840f62012-04-16 13:57:02 +03001722 mutex_unlock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001723 wl1271_warning("couldn't prepare device to suspend");
1724 return ret;
1725 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001726 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001727 mutex_unlock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 /* flush any remaining work */
1729 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001730
1731 /*
1732 * disable and re-enable interrupts in order to flush
1733 * the threaded_irq
1734 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001735 wlcore_disable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001736
1737 /*
1738 * set suspended flag to avoid triggering a new threaded_irq
1739 * work. no need for spinlock as interrupts are disabled.
1740 */
1741 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1742
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001743 wlcore_enable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001744 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 flush_delayed_work(&wl->elp_work);
1746
Eliad Peller402e48612011-05-13 11:57:09 +03001747 return 0;
1748}
1749
1750static int wl1271_op_resume(struct ieee80211_hw *hw)
1751{
1752 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001753 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001754 unsigned long flags;
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001755 bool run_irq_work = false, pending_recovery;
Arik Nemtsov725b8272012-06-21 18:10:52 +03001756 int ret;
Eliad Peller4a859df2011-06-06 12:21:52 +03001757
Eliad Peller402e48612011-05-13 11:57:09 +03001758 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1759 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001760 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001761
1762 /*
1763 * re-enable irq_work enqueuing, and call irq_work directly if
1764 * there is a pending work.
1765 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001766 spin_lock_irqsave(&wl->wl_lock, flags);
1767 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1768 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1769 run_irq_work = true;
1770 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001771
Arik Nemtsov725b8272012-06-21 18:10:52 +03001772 mutex_lock(&wl->mutex);
1773
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001774 /* test the recovery flag before calling any SDIO functions */
1775 pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
1776 &wl->flags);
1777
Eliad Peller4a859df2011-06-06 12:21:52 +03001778 if (run_irq_work) {
1779 wl1271_debug(DEBUG_MAC80211,
1780 "run postponed irq_work directly");
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001781
1782 /* don't talk to the HW if recovery is pending */
Arik Nemtsov725b8272012-06-21 18:10:52 +03001783 if (!pending_recovery) {
1784 ret = wlcore_irq_locked(wl);
1785 if (ret)
1786 wl12xx_queue_recovery_work(wl);
1787 }
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001788
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001789 wlcore_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001790 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001791
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001792 if (pending_recovery) {
1793 wl1271_warning("queuing forgotten recovery on resume");
1794 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1795 goto out;
1796 }
1797
Eliad Peller6e8cd332011-10-10 10:13:13 +02001798 wl12xx_for_each_wlvif(wl, wlvif) {
1799 wl1271_configure_resume(wl, wlvif);
1800 }
Arik Nemtsovea0a3cf2012-06-21 18:10:49 +03001801
1802out:
Eliad Pellerff91afc2011-06-06 12:21:53 +03001803 wl->wow_enabled = false;
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001804 mutex_unlock(&wl->mutex);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001805
Eliad Peller402e48612011-05-13 11:57:09 +03001806 return 0;
1807}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001808#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810static int wl1271_op_start(struct ieee80211_hw *hw)
1811{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001812 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1813
1814 /*
1815 * We have to delay the booting of the hardware because
1816 * we need to know the local MAC address before downloading and
1817 * initializing the firmware. The MAC address cannot be changed
1818 * after boot, and without the proper MAC address, the firmware
1819 * will not function properly.
1820 *
1821 * The MAC address is first known when the corresponding interface
1822 * is added. That is where we will initialize the hardware.
1823 */
1824
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001825 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001826}
1827
Ido Yarivc24ec832012-06-26 21:08:58 +03001828static void wlcore_op_stop_locked(struct wl1271 *wl)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001829{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001830 int i;
1831
Ido Yariv4cc53382012-07-24 19:18:49 +03001832 if (wl->state == WLCORE_STATE_OFF) {
Ido Yarivb666bb72012-05-21 01:10:11 +03001833 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
1834 &wl->flags))
1835 wlcore_enable_interrupts(wl);
1836
Eliad Peller10c8cd02011-10-10 10:13:06 +02001837 return;
1838 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001839
Eliad Pellerbaf62772011-10-10 10:12:52 +02001840 /*
1841 * this must be before the cancel_work calls below, so that the work
1842 * functions don't perform further work.
1843 */
Ido Yariv4cc53382012-07-24 19:18:49 +03001844 wl->state = WLCORE_STATE_OFF;
Ido Yarivc24ec832012-06-26 21:08:58 +03001845
1846 /*
1847 * Use the nosync variant to disable interrupts, so the mutex could be
1848 * held while doing so without deadlocking.
1849 */
1850 wlcore_disable_interrupts_nosync(wl);
1851
Eliad Peller10c8cd02011-10-10 10:13:06 +02001852 mutex_unlock(&wl->mutex);
1853
Ido Yarivc24ec832012-06-26 21:08:58 +03001854 wlcore_synchronize_interrupts(wl);
Eliad Peller6dbc5fc2012-07-29 14:37:29 +03001855 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1856 cancel_work_sync(&wl->recovery_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001857 wl1271_flush_deferred_work(wl);
1858 cancel_delayed_work_sync(&wl->scan_complete_work);
1859 cancel_work_sync(&wl->netstack_work);
1860 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001861 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001862 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001863
1864 /* let's notify MAC80211 about the remaining pending TX frames */
Eliad Pellerbaf62772011-10-10 10:12:52 +02001865 mutex_lock(&wl->mutex);
Arik Nemtsovd935e382012-11-27 08:44:53 +02001866 wl12xx_tx_reset(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001867
1868 wl1271_power_off(wl);
Ido Yarivb666bb72012-05-21 01:10:11 +03001869 /*
1870 * In case a recovery was scheduled, interrupts were disabled to avoid
1871 * an interrupt storm. Now that the power is down, it is safe to
1872 * re-enable interrupts to balance the disable depth
1873 */
1874 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1875 wlcore_enable_interrupts(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001876
1877 wl->band = IEEE80211_BAND_2GHZ;
1878
1879 wl->rx_counter = 0;
1880 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001881 wl->channel_type = NL80211_CHAN_NO_HT;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001882 wl->tx_blocks_available = 0;
1883 wl->tx_allocated_blocks = 0;
1884 wl->tx_results_count = 0;
1885 wl->tx_packets_count = 0;
1886 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001887 wl->ap_fw_ps_map = 0;
1888 wl->ap_ps_map = 0;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001889 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001890 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1891 memset(wl->links_map, 0, sizeof(wl->links_map));
1892 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Eliad Peller978cd3a2012-11-22 18:06:21 +02001893 memset(wl->session_ids, 0, sizeof(wl->session_ids));
Eliad Pellerbaf62772011-10-10 10:12:52 +02001894 wl->active_sta_count = 0;
Arik Nemtsov9a100962012-11-28 11:42:42 +02001895 wl->active_link_count = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001896
1897 /* The system link is always allocated */
Arik Nemtsov9ebcb232012-11-27 08:44:59 +02001898 wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0;
1899 wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001900 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1901
1902 /*
1903 * this is performed after the cancel_work calls and the associated
1904 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1905 * get executed before all these vars have been reset.
1906 */
1907 wl->flags = 0;
1908
1909 wl->tx_blocks_freed = 0;
1910
1911 for (i = 0; i < NUM_TX_QUEUES; i++) {
1912 wl->tx_pkts_freed[i] = 0;
1913 wl->tx_allocated_pkts[i] = 0;
1914 }
1915
1916 wl1271_debugfs_reset(wl);
1917
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001918 kfree(wl->fw_status_1);
1919 wl->fw_status_1 = NULL;
1920 wl->fw_status_2 = NULL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001921 kfree(wl->tx_res_if);
1922 wl->tx_res_if = NULL;
1923 kfree(wl->target_mem_map);
1924 wl->target_mem_map = NULL;
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02001925
1926 /*
1927 * FW channels must be re-calibrated after recovery,
1928 * clear the last Reg-Domain channel configuration.
1929 */
1930 memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));
Ido Yarivc24ec832012-06-26 21:08:58 +03001931}
1932
1933static void wlcore_op_stop(struct ieee80211_hw *hw)
1934{
1935 struct wl1271 *wl = hw->priv;
1936
1937 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1938
1939 mutex_lock(&wl->mutex);
1940
1941 wlcore_op_stop_locked(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001942
1943 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001944}
1945
Eliad Pellerc50a2822012-11-22 18:06:19 +02001946static void wlcore_channel_switch_work(struct work_struct *work)
1947{
1948 struct delayed_work *dwork;
1949 struct wl1271 *wl;
1950 struct ieee80211_vif *vif;
1951 struct wl12xx_vif *wlvif;
1952 int ret;
1953
1954 dwork = container_of(work, struct delayed_work, work);
1955 wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work);
1956 wl = wlvif->wl;
1957
1958 wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id);
1959
1960 mutex_lock(&wl->mutex);
1961
1962 if (unlikely(wl->state != WLCORE_STATE_ON))
1963 goto out;
1964
1965 /* check the channel switch is still ongoing */
1966 if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags))
1967 goto out;
1968
1969 vif = wl12xx_wlvif_to_vif(wlvif);
1970 ieee80211_chswitch_done(vif, false);
1971
1972 ret = wl1271_ps_elp_wakeup(wl);
1973 if (ret < 0)
1974 goto out;
1975
1976 wl12xx_cmd_stop_channel_switch(wl, wlvif);
1977
1978 wl1271_ps_elp_sleep(wl);
1979out:
1980 mutex_unlock(&wl->mutex);
1981}
1982
1983static void wlcore_connection_loss_work(struct work_struct *work)
1984{
1985 struct delayed_work *dwork;
1986 struct wl1271 *wl;
1987 struct ieee80211_vif *vif;
1988 struct wl12xx_vif *wlvif;
1989
1990 dwork = container_of(work, struct delayed_work, work);
1991 wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work);
1992 wl = wlvif->wl;
1993
1994 wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id);
1995
1996 mutex_lock(&wl->mutex);
1997
1998 if (unlikely(wl->state != WLCORE_STATE_ON))
1999 goto out;
2000
2001 /* Call mac80211 connection loss */
2002 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
2003 goto out;
2004
2005 vif = wl12xx_wlvif_to_vif(wlvif);
2006 ieee80211_connection_loss(vif);
2007out:
2008 mutex_unlock(&wl->mutex);
2009}
2010
Eliad Pellere5a359f2011-10-10 10:13:15 +02002011static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
2012{
2013 u8 policy = find_first_zero_bit(wl->rate_policies_map,
2014 WL12XX_MAX_RATE_POLICIES);
2015 if (policy >= WL12XX_MAX_RATE_POLICIES)
2016 return -EBUSY;
2017
2018 __set_bit(policy, wl->rate_policies_map);
2019 *idx = policy;
2020 return 0;
2021}
2022
2023static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
2024{
2025 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
2026 return;
2027
2028 __clear_bit(*idx, wl->rate_policies_map);
2029 *idx = WL12XX_MAX_RATE_POLICIES;
2030}
2031
Eliad Peller001e39a2012-08-16 13:52:47 +03002032static int wlcore_allocate_klv_template(struct wl1271 *wl, u8 *idx)
2033{
2034 u8 policy = find_first_zero_bit(wl->klv_templates_map,
2035 WLCORE_MAX_KLV_TEMPLATES);
2036 if (policy >= WLCORE_MAX_KLV_TEMPLATES)
2037 return -EBUSY;
2038
2039 __set_bit(policy, wl->klv_templates_map);
2040 *idx = policy;
2041 return 0;
2042}
2043
2044static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx)
2045{
2046 if (WARN_ON(*idx >= WLCORE_MAX_KLV_TEMPLATES))
2047 return;
2048
2049 __clear_bit(*idx, wl->klv_templates_map);
2050 *idx = WLCORE_MAX_KLV_TEMPLATES;
2051}
2052
Eliad Peller536129c2011-10-05 11:55:45 +02002053static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002054{
Eliad Peller536129c2011-10-05 11:55:45 +02002055 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002056 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02002057 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03002058 return WL1271_ROLE_P2P_GO;
2059 else
2060 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002061
2062 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02002063 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03002064 return WL1271_ROLE_P2P_CL;
2065 else
2066 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002067
Eliad Peller227e81e2011-08-14 13:17:26 +03002068 case BSS_TYPE_IBSS:
2069 return WL1271_ROLE_IBSS;
2070
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002071 default:
Eliad Peller536129c2011-10-05 11:55:45 +02002072 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002073 }
2074 return WL12XX_INVALID_ROLE_TYPE;
2075}
2076
Eliad Peller83587502011-10-10 10:12:53 +02002077static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002078{
Eliad Pellere936bbe2011-10-05 11:55:56 +02002079 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002080 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002081
Eliad Peller48e93e42011-10-10 10:12:58 +02002082 /* clear everything but the persistent data */
2083 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02002084
2085 switch (ieee80211_vif_type_p2p(vif)) {
2086 case NL80211_IFTYPE_P2P_CLIENT:
2087 wlvif->p2p = 1;
2088 /* fall-through */
2089 case NL80211_IFTYPE_STATION:
2090 wlvif->bss_type = BSS_TYPE_STA_BSS;
2091 break;
2092 case NL80211_IFTYPE_ADHOC:
2093 wlvif->bss_type = BSS_TYPE_IBSS;
2094 break;
2095 case NL80211_IFTYPE_P2P_GO:
2096 wlvif->p2p = 1;
2097 /* fall-through */
2098 case NL80211_IFTYPE_AP:
2099 wlvif->bss_type = BSS_TYPE_AP_BSS;
2100 break;
2101 default:
2102 wlvif->bss_type = MAX_BSS_TYPE;
2103 return -EOPNOTSUPP;
2104 }
2105
Eliad Peller0603d892011-10-05 11:55:51 +02002106 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002107 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002108 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002109
Eliad Pellere936bbe2011-10-05 11:55:56 +02002110 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2111 wlvif->bss_type == BSS_TYPE_IBSS) {
2112 /* init sta/ibss data */
2113 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002114 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2115 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2116 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Peller001e39a2012-08-16 13:52:47 +03002117 wlcore_allocate_klv_template(wl, &wlvif->sta.klv_template_id);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002118 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
2119 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
2120 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002121 } else {
2122 /* init ap data */
2123 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2124 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002125 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2126 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2127 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2128 wl12xx_allocate_rate_policy(wl,
2129 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller42ec1f82012-11-20 13:20:08 +02002130 wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002131 /*
2132 * TODO: check if basic_rate shouldn't be
2133 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2134 * instead (the same thing for STA above).
2135 */
Eliad Peller42ec1f82012-11-20 13:20:08 +02002136 wlvif->basic_rate = CONF_TX_ENABLED_RATES;
Luciano Coelho15e05bc2012-05-10 12:14:05 +03002137 /* TODO: this seems to be used only for STA, check it */
Eliad Peller42ec1f82012-11-20 13:20:08 +02002138 wlvif->rate_set = CONF_TX_ENABLED_RATES;
Eliad Pellere936bbe2011-10-05 11:55:56 +02002139 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002140
Eliad Peller83587502011-10-10 10:12:53 +02002141 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2142 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller6a899792011-10-05 11:55:58 +02002143 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2144
Eliad Peller1b92f152011-10-10 10:13:09 +02002145 /*
2146 * mac80211 configures some values globally, while we treat them
2147 * per-interface. thus, on init, we have to copy them from wl
2148 */
2149 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002150 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002151 wlvif->power_level = wl->power_level;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002152 wlvif->channel_type = wl->channel_type;
Eliad Peller1b92f152011-10-10 10:13:09 +02002153
Eliad Peller9eb599e2011-10-10 10:12:59 +02002154 INIT_WORK(&wlvif->rx_streaming_enable_work,
2155 wl1271_rx_streaming_enable_work);
2156 INIT_WORK(&wlvif->rx_streaming_disable_work,
2157 wl1271_rx_streaming_disable_work);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002158 INIT_DELAYED_WORK(&wlvif->channel_switch_work,
2159 wlcore_channel_switch_work);
2160 INIT_DELAYED_WORK(&wlvif->connection_loss_work,
2161 wlcore_connection_loss_work);
Eliad Peller87627212011-10-10 10:12:54 +02002162 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002163
Eliad Peller9eb599e2011-10-10 10:12:59 +02002164 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2165 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002166 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002167}
2168
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002169static int wl12xx_init_fw(struct wl1271 *wl)
Eliad Peller1d095472011-10-10 10:12:49 +02002170{
2171 int retries = WL1271_BOOT_RETRIES;
2172 bool booted = false;
2173 struct wiphy *wiphy = wl->hw->wiphy;
2174 int ret;
2175
2176 while (retries) {
2177 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02002178 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02002179 if (ret < 0)
2180 goto power_off;
2181
Luciano Coelhodd5512e2012-04-11 11:03:14 +03002182 ret = wl->ops->boot(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02002183 if (ret < 0)
2184 goto power_off;
2185
2186 ret = wl1271_hw_init(wl);
2187 if (ret < 0)
2188 goto irq_disable;
2189
2190 booted = true;
2191 break;
2192
2193irq_disable:
2194 mutex_unlock(&wl->mutex);
2195 /* Unlocking the mutex in the middle of handling is
2196 inherently unsafe. In this case we deem it safe to do,
2197 because we need to let any possibly pending IRQ out of
Ido Yariv4cc53382012-07-24 19:18:49 +03002198 the system (and while we are WLCORE_STATE_OFF the IRQ
Eliad Peller1d095472011-10-10 10:12:49 +02002199 work function will not do anything.) Also, any other
2200 possible concurrent operations will fail due to the
2201 current state, hence the wl1271 struct should be safe. */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03002202 wlcore_disable_interrupts(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02002203 wl1271_flush_deferred_work(wl);
2204 cancel_work_sync(&wl->netstack_work);
2205 mutex_lock(&wl->mutex);
2206power_off:
2207 wl1271_power_off(wl);
2208 }
2209
2210 if (!booted) {
2211 wl1271_error("firmware boot failed despite %d retries",
2212 WL1271_BOOT_RETRIES);
2213 goto out;
2214 }
2215
2216 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2217
2218 /* update hw/fw version info in wiphy struct */
2219 wiphy->hw_version = wl->chip.id;
2220 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2221 sizeof(wiphy->fw_version));
2222
2223 /*
2224 * Now we know if 11a is supported (info from the NVS), so disable
2225 * 11a channels if not supported
2226 */
2227 if (!wl->enable_11a)
2228 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2229
2230 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2231 wl->enable_11a ? "" : "not ");
2232
Ido Yariv4cc53382012-07-24 19:18:49 +03002233 wl->state = WLCORE_STATE_ON;
Eliad Peller1d095472011-10-10 10:12:49 +02002234out:
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002235 return ret;
Eliad Peller1d095472011-10-10 10:12:49 +02002236}
2237
Eliad Peller92e712d2011-12-18 20:25:43 +02002238static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2239{
2240 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2241}
2242
Eliad Peller4549d092012-02-06 13:07:52 +02002243/*
2244 * Check whether a fw switch (i.e. moving from one loaded
2245 * fw to another) is needed. This function is also responsible
2246 * for updating wl->last_vif_count, so it must be called before
2247 * loading a non-plt fw (so the correct fw (single-role/multi-role)
2248 * will be used).
2249 */
2250static bool wl12xx_need_fw_change(struct wl1271 *wl,
2251 struct vif_counter_data vif_counter_data,
2252 bool add)
2253{
2254 enum wl12xx_fw_type current_fw = wl->fw_type;
2255 u8 vif_count = vif_counter_data.counter;
2256
2257 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
2258 return false;
2259
2260 /* increase the vif count if this is a new vif */
2261 if (add && !vif_counter_data.cur_vif_running)
2262 vif_count++;
2263
2264 wl->last_vif_count = vif_count;
2265
2266 /* no need for fw change if the device is OFF */
Ido Yariv4cc53382012-07-24 19:18:49 +03002267 if (wl->state == WLCORE_STATE_OFF)
Eliad Peller4549d092012-02-06 13:07:52 +02002268 return false;
2269
Eliad Peller9b1a0a72012-07-25 14:22:21 +03002270 /* no need for fw change if a single fw is used */
2271 if (!wl->mr_fw_name)
2272 return false;
2273
Eliad Peller4549d092012-02-06 13:07:52 +02002274 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2275 return true;
2276 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2277 return true;
2278
2279 return false;
2280}
2281
Eliad Peller3dee4392012-02-06 12:47:56 +02002282/*
2283 * Enter "forced psm". Make sure the sta is in psm against the ap,
2284 * to make the fw switch a bit more disconnection-persistent.
2285 */
2286static void wl12xx_force_active_psm(struct wl1271 *wl)
2287{
2288 struct wl12xx_vif *wlvif;
2289
2290 wl12xx_for_each_wlvif_sta(wl, wlvif) {
2291 wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
2292 }
2293}
2294
Arik Nemtsov1c33db72012-11-30 00:48:03 +02002295struct wlcore_hw_queue_iter_data {
2296 unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)];
2297 /* current vif */
2298 struct ieee80211_vif *vif;
2299 /* is the current vif among those iterated */
2300 bool cur_running;
2301};
2302
2303static void wlcore_hw_queue_iter(void *data, u8 *mac,
2304 struct ieee80211_vif *vif)
2305{
2306 struct wlcore_hw_queue_iter_data *iter_data = data;
2307
2308 if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))
2309 return;
2310
2311 if (iter_data->cur_running || vif == iter_data->vif) {
2312 iter_data->cur_running = true;
2313 return;
2314 }
2315
2316 __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map);
2317}
2318
2319static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,
2320 struct wl12xx_vif *wlvif)
2321{
2322 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2323 struct wlcore_hw_queue_iter_data iter_data = {};
2324 int i, q_base;
2325
2326 iter_data.vif = vif;
2327
2328 /* mark all bits taken by active interfaces */
2329 ieee80211_iterate_active_interfaces_atomic(wl->hw,
2330 IEEE80211_IFACE_ITER_RESUME_ALL,
2331 wlcore_hw_queue_iter, &iter_data);
2332
2333 /* the current vif is already running in mac80211 (resume/recovery) */
2334 if (iter_data.cur_running) {
2335 wlvif->hw_queue_base = vif->hw_queue[0];
2336 wl1271_debug(DEBUG_MAC80211,
2337 "using pre-allocated hw queue base %d",
2338 wlvif->hw_queue_base);
2339
2340 /* interface type might have changed type */
2341 goto adjust_cab_queue;
2342 }
2343
2344 q_base = find_first_zero_bit(iter_data.hw_queue_map,
2345 WLCORE_NUM_MAC_ADDRESSES);
2346 if (q_base >= WLCORE_NUM_MAC_ADDRESSES)
2347 return -EBUSY;
2348
2349 wlvif->hw_queue_base = q_base * NUM_TX_QUEUES;
2350 wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d",
2351 wlvif->hw_queue_base);
2352
2353 for (i = 0; i < NUM_TX_QUEUES; i++) {
2354 wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0;
2355 /* register hw queues in mac80211 */
2356 vif->hw_queue[i] = wlvif->hw_queue_base + i;
2357 }
2358
2359adjust_cab_queue:
2360 /* the last places are reserved for cab queues per interface */
2361 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2362 vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES +
2363 wlvif->hw_queue_base / NUM_TX_QUEUES;
2364 else
2365 vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
2366
2367 return 0;
2368}
2369
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002370static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2371 struct ieee80211_vif *vif)
2372{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002374 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4549d092012-02-06 13:07:52 +02002375 struct vif_counter_data vif_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002377 u8 role_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378
Johannes Bergea086352012-01-19 09:29:58 +01002379 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2380 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002381
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002382 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002383 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384
Eliad Peller4549d092012-02-06 13:07:52 +02002385 wl12xx_get_vif_count(hw, vif, &vif_count);
2386
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002388 ret = wl1271_ps_elp_wakeup(wl);
2389 if (ret < 0)
2390 goto out_unlock;
2391
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002392 /*
2393 * in some very corner case HW recovery scenarios its possible to
2394 * get here before __wl1271_op_remove_interface is complete, so
2395 * opt out if that is the case.
2396 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002397 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2398 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002399 ret = -EBUSY;
2400 goto out;
2401 }
2402
Eliad Peller3fcdab72012-02-06 12:47:54 +02002403
Eliad Peller83587502011-10-10 10:12:53 +02002404 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002405 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002406 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002407
Eliad Peller252efa42011-10-05 11:56:00 +02002408 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002409 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002410 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2411 ret = -EINVAL;
2412 goto out;
2413 }
Eliad Peller1d095472011-10-10 10:12:49 +02002414
Arik Nemtsov1c33db72012-11-30 00:48:03 +02002415 ret = wlcore_allocate_hw_queue_base(wl, wlvif);
2416 if (ret < 0)
2417 goto out;
2418
Eliad Peller4549d092012-02-06 13:07:52 +02002419 if (wl12xx_need_fw_change(wl, vif_count, true)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002420 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002421 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002422 mutex_unlock(&wl->mutex);
2423 wl1271_recovery_work(&wl->recovery_work);
2424 return 0;
2425 }
2426
Eliad Peller784f6942011-10-05 11:55:39 +02002427 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002428 * TODO: after the nvs issue will be solved, move this block
2429 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002430 */
Ido Yariv4cc53382012-07-24 19:18:49 +03002431 if (wl->state == WLCORE_STATE_OFF) {
Eliad Peller1d095472011-10-10 10:12:49 +02002432 /*
2433 * we still need this in order to configure the fw
2434 * while uploading the nvs
2435 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002436 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437
Luciano Coelho5dc283f2013-01-30 10:53:14 +02002438 ret = wl12xx_init_fw(wl);
2439 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002440 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002441 }
Eliad Peller04e80792011-08-14 13:17:09 +03002442
Eliad Peller1d095472011-10-10 10:12:49 +02002443 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2444 role_type, &wlvif->role_id);
2445 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002446 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002447
2448 ret = wl1271_init_vif_specific(wl, vif);
2449 if (ret < 0)
2450 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002451
Eliad Peller87627212011-10-10 10:12:54 +02002452 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002453 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002454
2455 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2456 wl->ap_count++;
2457 else
2458 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002459out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002460 wl1271_ps_elp_sleep(wl);
2461out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002462 mutex_unlock(&wl->mutex);
2463
2464 return ret;
2465}
2466
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002467static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002468 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002469 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470{
Eliad Peller536129c2011-10-05 11:55:45 +02002471 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002472 int i, ret;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002473 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002475 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002476
Eliad Peller10c8cd02011-10-10 10:13:06 +02002477 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2478 return;
2479
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002480 /* because of hardware recovery, we may get here twice */
Ido Yariv4cc53382012-07-24 19:18:49 +03002481 if (wl->state == WLCORE_STATE_OFF)
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002482 return;
2483
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002484 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485
Eliad Pellerbaf62772011-10-10 10:12:52 +02002486 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
Eliad Pellerc50a2822012-11-22 18:06:19 +02002487 wl->scan_wlvif == wlvif) {
Arik Nemtsov55df5af2012-03-03 22:18:00 +02002488 /*
2489 * Rearm the tx watchdog just before idling scan. This
2490 * prevents just-finished scans from triggering the watchdog
2491 */
2492 wl12xx_rearm_tx_watchdog_locked(wl);
2493
Luciano Coelho08688d62010-07-08 17:50:07 +03002494 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002495 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Pellerc50a2822012-11-22 18:06:19 +02002496 wl->scan_wlvif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002497 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002498 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002499 }
2500
Eliad Peller10199752012-11-22 18:06:23 +02002501 if (wl->sched_vif == wlvif) {
2502 ieee80211_sched_scan_stopped(wl->hw);
2503 wl->sched_vif = NULL;
2504 }
2505
Arik Nemtsov5d979f32012-11-27 08:44:48 +02002506 if (wl->roc_vif == vif) {
2507 wl->roc_vif = NULL;
2508 ieee80211_remain_on_channel_expired(wl->hw);
2509 }
2510
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002511 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2512 /* disable active roles */
2513 ret = wl1271_ps_elp_wakeup(wl);
2514 if (ret < 0)
2515 goto deinit;
2516
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002517 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2518 wlvif->bss_type == BSS_TYPE_IBSS) {
2519 if (wl12xx_dev_role_started(wlvif))
2520 wl12xx_stop_dev(wl, wlvif);
Eliad Peller04e80792011-08-14 13:17:09 +03002521 }
2522
Eliad Peller0603d892011-10-05 11:55:51 +02002523 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002524 if (ret < 0)
2525 goto deinit;
2526
2527 wl1271_ps_elp_sleep(wl);
2528 }
2529deinit:
Arik Nemtsov5a996102013-03-12 17:19:43 +02002530 wl12xx_tx_reset_wlvif(wl, wlvif);
2531
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002532 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002533 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002534
2535 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2536 wlvif->bss_type == BSS_TYPE_IBSS) {
2537 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2538 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2539 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2540 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Peller001e39a2012-08-16 13:52:47 +03002541 wlcore_free_klv_template(wl, &wlvif->sta.klv_template_id);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002542 } else {
2543 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2544 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2545 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2546 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2547 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2548 wl12xx_free_rate_policy(wl,
2549 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller830be7e2012-03-19 11:32:55 +02002550 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002551 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002552
Eyal Shapira3eba4a02012-03-19 12:06:27 +02002553 dev_kfree_skb(wlvif->probereq);
2554 wlvif->probereq = NULL;
Eliad Pellere4120df2011-10-10 10:13:17 +02002555 if (wl->last_wlvif == wlvif)
2556 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002557 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002558 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002559 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002560 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002561
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002562 if (is_ap)
Eliad Pellera4e41302011-10-11 11:49:15 +02002563 wl->ap_count--;
2564 else
2565 wl->sta_count--;
2566
Arik Nemtsov42066f92012-07-10 10:45:01 +03002567 /*
2568 * Last AP, have more stations. Configure sleep auth according to STA.
2569 * Don't do thin on unintended recovery.
2570 */
2571 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) &&
2572 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags))
2573 goto unlock;
2574
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002575 if (wl->ap_count == 0 && is_ap && wl->sta_count) {
2576 u8 sta_auth = wl->conf.conn.sta_sleep_auth;
2577 /* Configure for power according to debugfs */
2578 if (sta_auth != WL1271_PSM_ILLEGAL)
2579 wl1271_acx_sleep_auth(wl, sta_auth);
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002580 /* Configure for ELP power saving */
2581 else
2582 wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
2583 }
2584
Arik Nemtsov42066f92012-07-10 10:45:01 +03002585unlock:
Eliad Pellerbaf62772011-10-10 10:12:52 +02002586 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002587
Eliad Peller9eb599e2011-10-10 10:12:59 +02002588 del_timer_sync(&wlvif->rx_streaming_timer);
2589 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2590 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002591 cancel_delayed_work_sync(&wlvif->connection_loss_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002592
Eliad Pellerbaf62772011-10-10 10:12:52 +02002593 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002594}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002595
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002596static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2597 struct ieee80211_vif *vif)
2598{
2599 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002600 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002601 struct wl12xx_vif *iter;
Eliad Peller4549d092012-02-06 13:07:52 +02002602 struct vif_counter_data vif_count;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002603
Eliad Peller4549d092012-02-06 13:07:52 +02002604 wl12xx_get_vif_count(hw, vif, &vif_count);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002605 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002606
Ido Yariv4cc53382012-07-24 19:18:49 +03002607 if (wl->state == WLCORE_STATE_OFF ||
Eliad Peller10c8cd02011-10-10 10:13:06 +02002608 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2609 goto out;
2610
Juuso Oikarinen67353292010-11-18 15:19:02 +02002611 /*
2612 * wl->vif can be null here if someone shuts down the interface
2613 * just when hardware recovery has been started.
2614 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002615 wl12xx_for_each_wlvif(wl, iter) {
2616 if (iter != wlvif)
2617 continue;
2618
Eliad Peller536129c2011-10-05 11:55:45 +02002619 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002620 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002621 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002622 WARN_ON(iter != wlvif);
Eliad Peller4549d092012-02-06 13:07:52 +02002623 if (wl12xx_need_fw_change(wl, vif_count, false)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002624 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002625 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002626 wl12xx_queue_recovery_work(wl);
Eliad Peller4549d092012-02-06 13:07:52 +02002627 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002628out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002629 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630}
2631
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002632static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2633 struct ieee80211_vif *vif,
2634 enum nl80211_iftype new_type, bool p2p)
2635{
Eliad Peller4549d092012-02-06 13:07:52 +02002636 struct wl1271 *wl = hw->priv;
2637 int ret;
2638
2639 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002640 wl1271_op_remove_interface(hw, vif);
2641
Eliad Peller249e9692012-03-04 10:55:50 +02002642 vif->type = new_type;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002643 vif->p2p = p2p;
Eliad Peller4549d092012-02-06 13:07:52 +02002644 ret = wl1271_op_add_interface(hw, vif);
2645
2646 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2647 return ret;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002648}
2649
Eliad Peller3230f352012-11-20 13:20:01 +02002650static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002651{
2652 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002653 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002654
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002655 /*
2656 * One of the side effects of the JOIN command is that is clears
2657 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2658 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002659 * Currently the only valid scenario for JOIN during association
2660 * is on roaming, in which case we will also be given new keys.
2661 * Keep the below message for now, unless it starts bothering
2662 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002663 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002664 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002665 wl1271_info("JOIN while associated.");
2666
Eliad Peller5ec8a442012-02-02 12:22:09 +02002667 /* clear encryption type */
2668 wlvif->encryption_type = KEY_NONE;
2669
Eliad Peller227e81e2011-08-14 13:17:26 +03002670 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002671 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller18eab432012-11-20 13:20:02 +02002672 else {
2673 if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
2674 /*
2675 * TODO: this is an ugly workaround for wl12xx fw
2676 * bug - we are not able to tx/rx after the first
2677 * start_sta, so make dummy start+stop calls,
2678 * and then call start_sta again.
2679 * this should be fixed in the fw.
2680 */
2681 wl12xx_cmd_role_start_sta(wl, wlvif);
2682 wl12xx_cmd_role_stop_sta(wl, wlvif);
2683 }
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002684
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002685 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Eliad Peller18eab432012-11-20 13:20:02 +02002686 }
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002687
Eliad Peller3230f352012-11-20 13:20:01 +02002688 return ret;
2689}
2690
2691static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb,
2692 int offset)
2693{
2694 u8 ssid_len;
2695 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2696 skb->len - offset);
2697
2698 if (!ptr) {
2699 wl1271_error("No SSID in IEs!");
2700 return -ENOENT;
2701 }
2702
2703 ssid_len = ptr[1];
2704 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2705 wl1271_error("SSID is too long!");
2706 return -EINVAL;
2707 }
2708
2709 wlvif->ssid_len = ssid_len;
2710 memcpy(wlvif->ssid, ptr+2, ssid_len);
2711 return 0;
2712}
2713
2714static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
2715{
2716 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2717 struct sk_buff *skb;
2718 int ieoffset;
2719
2720 /* we currently only support setting the ssid from the ap probe req */
2721 if (wlvif->bss_type != BSS_TYPE_STA_BSS)
2722 return -EINVAL;
2723
2724 skb = ieee80211_ap_probereq_get(wl->hw, vif);
2725 if (!skb)
2726 return -EINVAL;
2727
2728 ieoffset = offsetof(struct ieee80211_mgmt,
2729 u.probe_req.variable);
2730 wl1271_ssid_set(wlvif, skb, ieoffset);
2731 dev_kfree_skb(skb);
2732
2733 return 0;
2734}
2735
2736static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
Eliad Pellerec870112012-11-20 13:20:09 +02002737 struct ieee80211_bss_conf *bss_conf,
2738 u32 sta_rate_set)
Eliad Peller3230f352012-11-20 13:20:01 +02002739{
2740 int ieoffset;
2741 int ret;
2742
2743 wlvif->aid = bss_conf->aid;
Luciano Coelhoaaabee82012-12-04 16:39:47 +02002744 wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef);
Eliad Peller3230f352012-11-20 13:20:01 +02002745 wlvif->beacon_int = bss_conf->beacon_int;
Eliad Pellerd50529c2012-11-22 18:06:20 +02002746 wlvif->wmm_enabled = bss_conf->qos;
Eliad Peller3230f352012-11-20 13:20:01 +02002747
2748 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
2749
2750 /*
2751 * with wl1271, we don't need to update the
2752 * beacon_int and dtim_period, because the firmware
2753 * updates it by itself when the first beacon is
2754 * received after a join.
2755 */
2756 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
2757 if (ret < 0)
2758 return ret;
2759
2760 /*
2761 * Get a template for hardware connection maintenance
2762 */
2763 dev_kfree_skb(wlvif->probereq);
2764 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
2765 wlvif,
2766 NULL);
2767 ieoffset = offsetof(struct ieee80211_mgmt,
2768 u.probe_req.variable);
2769 wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset);
2770
2771 /* enable the connection monitoring feature */
2772 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
2773 if (ret < 0)
2774 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002775
2776 /*
2777 * The join command disable the keep-alive mode, shut down its process,
2778 * and also clear the template config, so we need to reset it all after
2779 * the join. The acx_aid starts the keep-alive process, and the order
2780 * of the commands below is relevant.
2781 */
Eliad Peller0603d892011-10-05 11:55:51 +02002782 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002783 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002784 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002785
Eliad Peller0603d892011-10-05 11:55:51 +02002786 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002787 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002788 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002789
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002790 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002791 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002792 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002793
Eliad Peller0603d892011-10-05 11:55:51 +02002794 ret = wl1271_acx_keep_alive_config(wl, wlvif,
Eliad Peller001e39a2012-08-16 13:52:47 +03002795 wlvif->sta.klv_template_id,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002796 ACX_KEEP_ALIVE_TPL_VALID);
2797 if (ret < 0)
Eliad Peller3230f352012-11-20 13:20:01 +02002798 return ret;
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002799
Eliad Peller6c7b5192012-11-20 13:20:07 +02002800 /*
2801 * The default fw psm configuration is AUTO, while mac80211 default
2802 * setting is off (ACTIVE), so sync the fw with the correct value.
2803 */
2804 ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE);
Eliad Pellerec870112012-11-20 13:20:09 +02002805 if (ret < 0)
2806 return ret;
2807
2808 if (sta_rate_set) {
2809 wlvif->rate_set =
2810 wl1271_tx_enabled_rates_get(wl,
2811 sta_rate_set,
2812 wlvif->band);
2813 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
2814 if (ret < 0)
2815 return ret;
2816 }
Eliad Peller6c7b5192012-11-20 13:20:07 +02002817
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002818 return ret;
2819}
2820
Eliad Peller3230f352012-11-20 13:20:01 +02002821static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002822{
2823 int ret;
Eliad Peller3230f352012-11-20 13:20:01 +02002824 bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
2825
2826 /* make sure we are connected (sta) joined */
2827 if (sta &&
2828 !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
2829 return false;
2830
2831 /* make sure we are joined (ibss) */
2832 if (!sta &&
2833 test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))
2834 return false;
2835
2836 if (sta) {
2837 /* use defaults when not associated */
2838 wlvif->aid = 0;
2839
2840 /* free probe-request template */
2841 dev_kfree_skb(wlvif->probereq);
2842 wlvif->probereq = NULL;
2843
2844 /* disable connection monitor features */
2845 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
2846 if (ret < 0)
2847 return ret;
2848
2849 /* Disable the keep-alive feature */
2850 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
2851 if (ret < 0)
2852 return ret;
2853 }
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002854
Eliad Peller52630c52011-10-10 10:13:08 +02002855 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002856 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2857
Eliad Pellerfcab1892012-11-22 18:06:18 +02002858 wl12xx_cmd_stop_channel_switch(wl, wlvif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002859 ieee80211_chswitch_done(vif, false);
Eliad Pellerc50a2822012-11-22 18:06:19 +02002860 cancel_delayed_work(&wlvif->channel_switch_work);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002861 }
2862
Eliad Peller4137c172012-08-16 13:32:32 +03002863 /* invalidate keep-alive template */
2864 wl1271_acx_keep_alive_config(wl, wlvif,
Eliad Peller001e39a2012-08-16 13:52:47 +03002865 wlvif->sta.klv_template_id,
Eliad Peller4137c172012-08-16 13:32:32 +03002866 ACX_KEEP_ALIVE_TPL_INVALID);
2867
Eliad Peller3230f352012-11-20 13:20:01 +02002868 return 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002869}
2870
Eliad Peller87fbcb02011-10-05 11:55:41 +02002871static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002872{
Eliad Peller1b92f152011-10-10 10:13:09 +02002873 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002874 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002875}
2876
Eliad Peller9f259c42011-10-10 10:13:12 +02002877static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2878 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002879{
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002880 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002881
Eliad Peller6bd65022011-10-10 10:13:11 +02002882 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002883 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002884 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002885 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002886
Eliad Peller6bd65022011-10-10 10:13:11 +02002887 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002888 }
2889
Eliad Peller9f259c42011-10-10 10:13:12 +02002890 return 0;
2891}
2892
2893static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2894{
2895 struct wl1271 *wl = hw->priv;
2896 struct wl12xx_vif *wlvif;
2897 struct ieee80211_conf *conf = &hw->conf;
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002898 int ret = 0;
Eliad Peller9f259c42011-10-10 10:13:12 +02002899
Eliad Pellerb6970ee2012-11-20 13:20:05 +02002900 wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
Eliad Peller9f259c42011-10-10 10:13:12 +02002901 " changed 0x%x",
Eliad Peller9f259c42011-10-10 10:13:12 +02002902 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2903 conf->power_level,
2904 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2905 changed);
2906
Eliad Peller9f259c42011-10-10 10:13:12 +02002907 mutex_lock(&wl->mutex);
2908
Eliad Peller9f259c42011-10-10 10:13:12 +02002909 if (changed & IEEE80211_CONF_CHANGE_POWER)
2910 wl->power_level = conf->power_level;
2911
Ido Yariv4cc53382012-07-24 19:18:49 +03002912 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Peller9f259c42011-10-10 10:13:12 +02002913 goto out;
2914
2915 ret = wl1271_ps_elp_wakeup(wl);
2916 if (ret < 0)
2917 goto out;
2918
2919 /* configure each interface */
2920 wl12xx_for_each_wlvif(wl, wlvif) {
2921 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2922 if (ret < 0)
2923 goto out_sleep;
2924 }
2925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926out_sleep:
2927 wl1271_ps_elp_sleep(wl);
2928
2929out:
2930 mutex_unlock(&wl->mutex);
2931
2932 return ret;
2933}
2934
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002935struct wl1271_filter_params {
2936 bool enabled;
2937 int mc_list_length;
2938 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2939};
2940
Jiri Pirko22bedad32010-04-01 21:22:57 +00002941static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2942 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002943{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002944 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002945 struct netdev_hw_addr *ha;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002946
Juuso Oikarinen74441132009-10-13 12:47:53 +03002947 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002948 if (!fp) {
2949 wl1271_error("Out of memory setting filters.");
2950 return 0;
2951 }
2952
2953 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002954 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002955 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2956 fp->enabled = false;
2957 } else {
2958 fp->enabled = true;
2959 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002960 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002961 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002962 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002963 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002964 }
2965
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002966 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002967}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002969#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2970 FIF_ALLMULTI | \
2971 FIF_FCSFAIL | \
2972 FIF_BCN_PRBRESP_PROMISC | \
2973 FIF_CONTROL | \
2974 FIF_OTHER_BSS)
2975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002976static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2977 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002978 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002980 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002982 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002983
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002984 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985
Arik Nemtsov7d057862010-10-16 19:25:35 +02002986 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2987 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002989 mutex_lock(&wl->mutex);
2990
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002991 *total &= WL1271_SUPPORTED_FILTERS;
2992 changed &= WL1271_SUPPORTED_FILTERS;
2993
Ido Yariv4cc53382012-07-24 19:18:49 +03002994 if (unlikely(wl->state != WLCORE_STATE_ON))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002995 goto out;
2996
Ido Yariva6208652011-03-01 15:14:41 +02002997 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002998 if (ret < 0)
2999 goto out;
3000
Eliad Peller6e8cd332011-10-10 10:13:13 +02003001 wl12xx_for_each_wlvif(wl, wlvif) {
3002 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
3003 if (*total & FIF_ALLMULTI)
3004 ret = wl1271_acx_group_address_tbl(wl, wlvif,
3005 false,
3006 NULL, 0);
3007 else if (fp)
3008 ret = wl1271_acx_group_address_tbl(wl, wlvif,
3009 fp->enabled,
3010 fp->mc_list,
3011 fp->mc_list_length);
3012 if (ret < 0)
3013 goto out_sleep;
3014 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02003015 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016
Eliad Peller08c1d1c2011-08-14 13:17:04 +03003017 /*
3018 * the fw doesn't provide an api to configure the filters. instead,
3019 * the filters configuration is based on the active roles / ROC
3020 * state.
3021 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03003022
3023out_sleep:
3024 wl1271_ps_elp_sleep(wl);
3025
3026out:
3027 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02003028 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029}
3030
Eliad Peller170d0e62011-10-05 11:56:06 +02003031static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3032 u8 id, u8 key_type, u8 key_size,
3033 const u8 *key, u8 hlid, u32 tx_seq_32,
3034 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003035{
3036 struct wl1271_ap_key *ap_key;
3037 int i;
3038
3039 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
3040
3041 if (key_size > MAX_KEY_SIZE)
3042 return -EINVAL;
3043
3044 /*
3045 * Find next free entry in ap_keys. Also check we are not replacing
3046 * an existing key.
3047 */
3048 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02003049 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003050 break;
3051
Eliad Peller170d0e62011-10-05 11:56:06 +02003052 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003053 wl1271_warning("trying to record key replacement");
3054 return -EINVAL;
3055 }
3056 }
3057
3058 if (i == MAX_NUM_KEYS)
3059 return -EBUSY;
3060
3061 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
3062 if (!ap_key)
3063 return -ENOMEM;
3064
3065 ap_key->id = id;
3066 ap_key->key_type = key_type;
3067 ap_key->key_size = key_size;
3068 memcpy(ap_key->key, key, key_size);
3069 ap_key->hlid = hlid;
3070 ap_key->tx_seq_32 = tx_seq_32;
3071 ap_key->tx_seq_16 = tx_seq_16;
3072
Eliad Peller170d0e62011-10-05 11:56:06 +02003073 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003074 return 0;
3075}
3076
Eliad Peller170d0e62011-10-05 11:56:06 +02003077static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003078{
3079 int i;
3080
3081 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02003082 kfree(wlvif->ap.recorded_keys[i]);
3083 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003084 }
3085}
3086
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003087static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003088{
3089 int i, ret = 0;
3090 struct wl1271_ap_key *key;
3091 bool wep_key_added = false;
3092
3093 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03003094 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02003095 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003096 break;
3097
Eliad Peller170d0e62011-10-05 11:56:06 +02003098 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03003099 hlid = key->hlid;
3100 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003101 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03003102
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003103 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003104 key->id, key->key_type,
3105 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03003106 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003107 key->tx_seq_16);
3108 if (ret < 0)
3109 goto out;
3110
3111 if (key->key_type == KEY_WEP)
3112 wep_key_added = true;
3113 }
3114
3115 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02003116 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003117 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003118 if (ret < 0)
3119 goto out;
3120 }
3121
3122out:
Eliad Peller170d0e62011-10-05 11:56:06 +02003123 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003124 return ret;
3125}
3126
Eliad Peller536129c2011-10-05 11:55:45 +02003127static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3128 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003129 u8 key_size, const u8 *key, u32 tx_seq_32,
3130 u16 tx_seq_16, struct ieee80211_sta *sta)
3131{
3132 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02003133 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003134
3135 if (is_ap) {
3136 struct wl1271_station *wl_sta;
3137 u8 hlid;
3138
3139 if (sta) {
3140 wl_sta = (struct wl1271_station *)sta->drv_priv;
3141 hlid = wl_sta->hlid;
3142 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003143 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003144 }
3145
Eliad Peller53d40d02011-10-10 10:13:02 +02003146 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003147 /*
3148 * We do not support removing keys after AP shutdown.
3149 * Pretend we do to make mac80211 happy.
3150 */
3151 if (action != KEY_ADD_OR_REPLACE)
3152 return 0;
3153
Eliad Peller170d0e62011-10-05 11:56:06 +02003154 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003155 key_type, key_size,
3156 key, hlid, tx_seq_32,
3157 tx_seq_16);
3158 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003159 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003160 id, key_type, key_size,
3161 key, hlid, tx_seq_32,
3162 tx_seq_16);
3163 }
3164
3165 if (ret < 0)
3166 return ret;
3167 } else {
3168 const u8 *addr;
3169 static const u8 bcast_addr[ETH_ALEN] = {
3170 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
3171 };
3172
3173 addr = sta ? sta->addr : bcast_addr;
3174
3175 if (is_zero_ether_addr(addr)) {
3176 /* We dont support TX only encryption */
3177 return -EOPNOTSUPP;
3178 }
3179
3180 /* The wl1271 does not allow to remove unicast keys - they
3181 will be cleared automatically on next CMD_JOIN. Ignore the
3182 request silently, as we dont want the mac80211 to emit
3183 an error message. */
3184 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
3185 return 0;
3186
Eliad Peller010d3d32011-08-14 13:17:31 +03003187 /* don't remove key if hlid was already deleted */
3188 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02003189 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03003190 return 0;
3191
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003192 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003193 id, key_type, key_size,
3194 key, addr, tx_seq_32,
3195 tx_seq_16);
3196 if (ret < 0)
3197 return ret;
3198
3199 /* the default WEP key needs to be configured at least once */
3200 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003201 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02003202 wlvif->default_key,
3203 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003204 if (ret < 0)
3205 return ret;
3206 }
3207 }
3208
3209 return 0;
3210}
3211
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003212static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213 struct ieee80211_vif *vif,
3214 struct ieee80211_sta *sta,
3215 struct ieee80211_key_conf *key_conf)
3216{
3217 struct wl1271 *wl = hw->priv;
Eliad Pelleraf390f42012-09-03 18:27:58 +03003218 int ret;
3219 bool might_change_spare =
3220 key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
3221 key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003222
Eliad Pelleraf390f42012-09-03 18:27:58 +03003223 if (might_change_spare) {
3224 /*
3225 * stop the queues and flush to ensure the next packets are
3226 * in sync with FW spare block accounting
3227 */
Eliad Pelleraf390f42012-09-03 18:27:58 +03003228 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003229 wl1271_tx_flush(wl);
3230 }
3231
3232 mutex_lock(&wl->mutex);
3233
3234 if (unlikely(wl->state != WLCORE_STATE_ON)) {
3235 ret = -EAGAIN;
3236 goto out_wake_queues;
3237 }
3238
3239 ret = wl1271_ps_elp_wakeup(wl);
3240 if (ret < 0)
3241 goto out_wake_queues;
3242
3243 ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
3244
3245 wl1271_ps_elp_sleep(wl);
3246
3247out_wake_queues:
3248 if (might_change_spare)
3249 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
3250
3251 mutex_unlock(&wl->mutex);
3252
3253 return ret;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003254}
3255
3256int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
3257 struct ieee80211_vif *vif,
3258 struct ieee80211_sta *sta,
3259 struct ieee80211_key_conf *key_conf)
3260{
Eliad Peller536129c2011-10-05 11:55:45 +02003261 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003262 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03003263 u32 tx_seq_32 = 0;
3264 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265 u8 key_type;
Arik Nemtsov93d5d102013-03-12 17:19:38 +02003266 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
3269
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003270 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003271 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02003272 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003273 key_conf->keylen, key_conf->flags);
3274 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
3275
Arik Nemtsov93d5d102013-03-12 17:19:38 +02003276 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
3277 if (sta) {
3278 struct wl1271_station *wl_sta = (void *)sta->drv_priv;
3279 hlid = wl_sta->hlid;
3280 } else {
3281 hlid = wlvif->ap.bcast_hlid;
3282 }
3283 else
3284 hlid = wlvif->sta.hlid;
3285
3286 if (hlid != WL12XX_INVALID_LINK_ID) {
3287 u64 tx_seq = wl->links[hlid].total_freed_pkts;
3288 tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq);
3289 tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq);
3290 }
3291
Johannes Berg97359d12010-08-10 09:46:38 +02003292 switch (key_conf->cipher) {
3293 case WLAN_CIPHER_SUITE_WEP40:
3294 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003295 key_type = KEY_WEP;
3296
3297 key_conf->hw_key_idx = key_conf->keyidx;
3298 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003299 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003300 key_type = KEY_TKIP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003301 key_conf->hw_key_idx = key_conf->keyidx;
3302 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003303 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003304 key_type = KEY_AES;
Arik Nemtsov12d4b972011-10-23 08:21:54 +02003305 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003307 case WL1271_CIPHER_SUITE_GEM:
3308 key_type = KEY_GEM;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003309 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003311 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003312
Eliad Pelleraf390f42012-09-03 18:27:58 +03003313 return -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003314 }
3315
3316 switch (cmd) {
3317 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003318 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003319 key_conf->keyidx, key_type,
3320 key_conf->keylen, key_conf->key,
3321 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003322 if (ret < 0) {
3323 wl1271_error("Could not add or replace key");
Eliad Pelleraf390f42012-09-03 18:27:58 +03003324 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02003326
3327 /*
3328 * reconfiguring arp response if the unicast (or common)
3329 * encryption key type was changed
3330 */
3331 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
3332 (sta || key_type == KEY_WEP) &&
3333 wlvif->encryption_type != key_type) {
3334 wlvif->encryption_type = key_type;
3335 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3336 if (ret < 0) {
3337 wl1271_warning("build arp rsp failed: %d", ret);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003338 return ret;
Eliad Peller5ec8a442012-02-02 12:22:09 +02003339 }
3340 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341 break;
3342
3343 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003344 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003345 key_conf->keyidx, key_type,
3346 key_conf->keylen, key_conf->key,
3347 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003348 if (ret < 0) {
3349 wl1271_error("Could not remove key");
Eliad Pelleraf390f42012-09-03 18:27:58 +03003350 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003351 }
3352 break;
3353
3354 default:
3355 wl1271_error("Unsupported key cmd 0x%x", cmd);
Eliad Pelleraf390f42012-09-03 18:27:58 +03003356 return -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003357 }
3358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359 return ret;
3360}
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003361EXPORT_SYMBOL_GPL(wlcore_set_key);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003362
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02003363void wlcore_regdomain_config(struct wl1271 *wl)
3364{
3365 int ret;
3366
3367 if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
3368 return;
3369
3370 mutex_lock(&wl->mutex);
Arik Nemtsov75592be2013-03-12 17:19:45 +02003371
3372 if (unlikely(wl->state != WLCORE_STATE_ON))
3373 goto out;
3374
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02003375 ret = wl1271_ps_elp_wakeup(wl);
3376 if (ret < 0)
3377 goto out;
3378
3379 ret = wlcore_cmd_regdomain_config_locked(wl);
3380 if (ret < 0) {
3381 wl12xx_queue_recovery_work(wl);
3382 goto out;
3383 }
3384
3385 wl1271_ps_elp_sleep(wl);
3386out:
3387 mutex_unlock(&wl->mutex);
3388}
3389
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003390static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003391 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003392 struct cfg80211_scan_request *req)
3393{
3394 struct wl1271 *wl = hw->priv;
3395 int ret;
3396 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003397 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003398
3399 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3400
3401 if (req->n_ssids) {
3402 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003403 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003404 }
3405
3406 mutex_lock(&wl->mutex);
3407
Ido Yariv4cc53382012-07-24 19:18:49 +03003408 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003409 /*
3410 * We cannot return -EBUSY here because cfg80211 will expect
3411 * a call to ieee80211_scan_completed if we do - in this case
3412 * there won't be any call.
3413 */
3414 ret = -EAGAIN;
3415 goto out;
3416 }
3417
Ido Yariva6208652011-03-01 15:14:41 +02003418 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419 if (ret < 0)
3420 goto out;
3421
Eliad Peller97fd3112012-03-04 10:55:52 +02003422 /* fail if there is any role in ROC */
3423 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
Eliad Peller92e712d2011-12-18 20:25:43 +02003424 /* don't allow scanning right now */
3425 ret = -EBUSY;
3426 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003427 }
3428
Eliad Peller78e28062012-11-22 18:06:15 +02003429 ret = wlcore_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003430out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003431 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003432out:
3433 mutex_unlock(&wl->mutex);
3434
3435 return ret;
3436}
3437
Eliad Peller73ecce32011-06-27 13:06:45 +03003438static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3439 struct ieee80211_vif *vif)
3440{
3441 struct wl1271 *wl = hw->priv;
Eliad Peller78e28062012-11-22 18:06:15 +02003442 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller73ecce32011-06-27 13:06:45 +03003443 int ret;
3444
3445 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3446
3447 mutex_lock(&wl->mutex);
3448
Ido Yariv4cc53382012-07-24 19:18:49 +03003449 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Peller73ecce32011-06-27 13:06:45 +03003450 goto out;
3451
3452 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3453 goto out;
3454
3455 ret = wl1271_ps_elp_wakeup(wl);
3456 if (ret < 0)
3457 goto out;
3458
3459 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
Eliad Peller78e28062012-11-22 18:06:15 +02003460 ret = wl->ops->scan_stop(wl, wlvif);
Eliad Peller73ecce32011-06-27 13:06:45 +03003461 if (ret < 0)
3462 goto out_sleep;
3463 }
Arik Nemtsov55df5af2012-03-03 22:18:00 +02003464
3465 /*
3466 * Rearm the tx watchdog just before idling scan. This
3467 * prevents just-finished scans from triggering the watchdog
3468 */
3469 wl12xx_rearm_tx_watchdog_locked(wl);
3470
Eliad Peller73ecce32011-06-27 13:06:45 +03003471 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3472 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Pellerc50a2822012-11-22 18:06:19 +02003473 wl->scan_wlvif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003474 wl->scan.req = NULL;
3475 ieee80211_scan_completed(wl->hw, true);
3476
3477out_sleep:
3478 wl1271_ps_elp_sleep(wl);
3479out:
3480 mutex_unlock(&wl->mutex);
3481
3482 cancel_delayed_work_sync(&wl->scan_complete_work);
3483}
3484
Luciano Coelho33c2c062011-05-10 14:46:02 +03003485static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3486 struct ieee80211_vif *vif,
3487 struct cfg80211_sched_scan_request *req,
3488 struct ieee80211_sched_scan_ies *ies)
3489{
3490 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003491 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003492 int ret;
3493
3494 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3495
3496 mutex_lock(&wl->mutex);
3497
Ido Yariv4cc53382012-07-24 19:18:49 +03003498 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003499 ret = -EAGAIN;
3500 goto out;
3501 }
3502
Luciano Coelho33c2c062011-05-10 14:46:02 +03003503 ret = wl1271_ps_elp_wakeup(wl);
3504 if (ret < 0)
3505 goto out;
3506
Eliad Peller78e28062012-11-22 18:06:15 +02003507 ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003508 if (ret < 0)
3509 goto out_sleep;
3510
Eliad Peller10199752012-11-22 18:06:23 +02003511 wl->sched_vif = wlvif;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003512
3513out_sleep:
3514 wl1271_ps_elp_sleep(wl);
3515out:
3516 mutex_unlock(&wl->mutex);
3517 return ret;
3518}
3519
3520static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3521 struct ieee80211_vif *vif)
3522{
3523 struct wl1271 *wl = hw->priv;
Yoni Divinsky78f85f52012-05-16 11:34:17 +03003524 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003525 int ret;
3526
3527 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3528
3529 mutex_lock(&wl->mutex);
3530
Ido Yariv4cc53382012-07-24 19:18:49 +03003531 if (unlikely(wl->state != WLCORE_STATE_ON))
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003532 goto out;
3533
Luciano Coelho33c2c062011-05-10 14:46:02 +03003534 ret = wl1271_ps_elp_wakeup(wl);
3535 if (ret < 0)
3536 goto out;
3537
Eliad Peller78e28062012-11-22 18:06:15 +02003538 wl->ops->sched_scan_stop(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003539
3540 wl1271_ps_elp_sleep(wl);
3541out:
3542 mutex_unlock(&wl->mutex);
3543}
3544
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003545static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3546{
3547 struct wl1271 *wl = hw->priv;
3548 int ret = 0;
3549
3550 mutex_lock(&wl->mutex);
3551
Ido Yariv4cc53382012-07-24 19:18:49 +03003552 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003553 ret = -EAGAIN;
3554 goto out;
3555 }
3556
Ido Yariva6208652011-03-01 15:14:41 +02003557 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003558 if (ret < 0)
3559 goto out;
3560
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003561 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003562 if (ret < 0)
3563 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3564
3565 wl1271_ps_elp_sleep(wl);
3566
3567out:
3568 mutex_unlock(&wl->mutex);
3569
3570 return ret;
3571}
3572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003573static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3574{
3575 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003576 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003577 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578
3579 mutex_lock(&wl->mutex);
3580
Ido Yariv4cc53382012-07-24 19:18:49 +03003581 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003582 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003583 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003584 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003585
Ido Yariva6208652011-03-01 15:14:41 +02003586 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003587 if (ret < 0)
3588 goto out;
3589
Eliad Peller6e8cd332011-10-10 10:13:13 +02003590 wl12xx_for_each_wlvif(wl, wlvif) {
3591 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3592 if (ret < 0)
3593 wl1271_warning("set rts threshold failed: %d", ret);
3594 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003595 wl1271_ps_elp_sleep(wl);
3596
3597out:
3598 mutex_unlock(&wl->mutex);
3599
3600 return ret;
3601}
3602
Eliad Pellerd48055d2011-09-15 12:07:04 +03003603static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3604{
3605 int len;
3606 const u8 *next, *end = skb->data + skb->len;
3607 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3608 skb->len - ieoffset);
3609 if (!ie)
3610 return;
3611 len = ie[1] + 2;
3612 next = ie + len;
3613 memmove(ie, next, end - next);
3614 skb_trim(skb, skb->len - len);
3615}
3616
Eliad Peller26b4bf22011-09-15 12:07:05 +03003617static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3618 unsigned int oui, u8 oui_type,
3619 int ieoffset)
3620{
3621 int len;
3622 const u8 *next, *end = skb->data + skb->len;
3623 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3624 skb->data + ieoffset,
3625 skb->len - ieoffset);
3626 if (!ie)
3627 return;
3628 len = ie[1] + 2;
3629 next = ie + len;
3630 memmove(ie, next, end - next);
3631 skb_trim(skb, skb->len - len);
3632}
3633
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003634static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3635 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003636{
Eliad Pellercdaac622012-01-31 11:57:16 +02003637 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003638 struct sk_buff *skb;
3639 int ret;
3640
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003641 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003642 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003643 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003644
Eliad Pellercdaac622012-01-31 11:57:16 +02003645 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003646 CMD_TEMPL_AP_PROBE_RESPONSE,
3647 skb->data,
3648 skb->len, 0,
3649 rates);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003650 dev_kfree_skb(skb);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003651
3652 if (ret < 0)
3653 goto out;
3654
3655 wl1271_debug(DEBUG_AP, "probe response updated");
3656 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3657
3658out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003659 return ret;
3660}
3661
3662static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3663 struct ieee80211_vif *vif,
3664 u8 *probe_rsp_data,
3665 size_t probe_rsp_len,
3666 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003667{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003668 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3669 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003670 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3671 int ssid_ie_offset, ie_offset, templ_len;
3672 const u8 *ptr;
3673
3674 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003675 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003676 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003677 CMD_TEMPL_AP_PROBE_RESPONSE,
3678 probe_rsp_data,
3679 probe_rsp_len, 0,
3680 rates);
3681
3682 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3683 wl1271_error("probe_rsp template too big");
3684 return -EINVAL;
3685 }
3686
3687 /* start searching from IE offset */
3688 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3689
3690 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3691 probe_rsp_len - ie_offset);
3692 if (!ptr) {
3693 wl1271_error("No SSID in beacon!");
3694 return -EINVAL;
3695 }
3696
3697 ssid_ie_offset = ptr - probe_rsp_data;
3698 ptr += (ptr[1] + 2);
3699
3700 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3701
3702 /* insert SSID from bss_conf */
3703 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3704 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3705 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3706 bss_conf->ssid, bss_conf->ssid_len);
3707 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3708
3709 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3710 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3711 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3712
Eliad Pellercdaac622012-01-31 11:57:16 +02003713 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003714 CMD_TEMPL_AP_PROBE_RESPONSE,
3715 probe_rsp_templ,
3716 templ_len, 0,
3717 rates);
3718}
3719
Arik Nemtsove78a2872010-10-16 19:07:21 +02003720static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003721 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003722 struct ieee80211_bss_conf *bss_conf,
3723 u32 changed)
3724{
Eliad Peller0603d892011-10-05 11:55:51 +02003725 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003726 int ret = 0;
3727
3728 if (changed & BSS_CHANGED_ERP_SLOT) {
3729 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003730 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003731 else
Eliad Peller0603d892011-10-05 11:55:51 +02003732 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003733 if (ret < 0) {
3734 wl1271_warning("Set slot time failed %d", ret);
3735 goto out;
3736 }
3737 }
3738
3739 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3740 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003741 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003742 else
Eliad Peller0603d892011-10-05 11:55:51 +02003743 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003744 }
3745
3746 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3747 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003748 ret = wl1271_acx_cts_protect(wl, wlvif,
3749 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003750 else
Eliad Peller0603d892011-10-05 11:55:51 +02003751 ret = wl1271_acx_cts_protect(wl, wlvif,
3752 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003753 if (ret < 0) {
3754 wl1271_warning("Set ctsprotect failed %d", ret);
3755 goto out;
3756 }
3757 }
3758
3759out:
3760 return ret;
3761}
3762
Luciano Coelho62c2e572012-05-10 12:14:04 +03003763static int wlcore_set_beacon_template(struct wl1271 *wl,
3764 struct ieee80211_vif *vif,
3765 bool is_ap)
3766{
3767 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3768 struct ieee80211_hdr *hdr;
3769 u32 min_rate;
3770 int ret;
Luciano Coelho8f6ac532013-05-04 01:06:11 +03003771 int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003772 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3773 u16 tmpl_id;
3774
3775 if (!beacon) {
3776 ret = -EINVAL;
3777 goto out;
3778 }
3779
3780 wl1271_debug(DEBUG_MASTER, "beacon updated");
3781
Eliad Peller3230f352012-11-20 13:20:01 +02003782 ret = wl1271_ssid_set(wlvif, beacon, ieoffset);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003783 if (ret < 0) {
3784 dev_kfree_skb(beacon);
3785 goto out;
3786 }
3787 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
3788 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3789 CMD_TEMPL_BEACON;
3790 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
3791 beacon->data,
3792 beacon->len, 0,
3793 min_rate);
3794 if (ret < 0) {
3795 dev_kfree_skb(beacon);
3796 goto out;
3797 }
3798
Eliad Pellerd50529c2012-11-22 18:06:20 +02003799 wlvif->wmm_enabled =
3800 cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
3801 WLAN_OUI_TYPE_MICROSOFT_WMM,
3802 beacon->data + ieoffset,
3803 beacon->len - ieoffset);
3804
Luciano Coelho62c2e572012-05-10 12:14:04 +03003805 /*
3806 * In case we already have a probe-resp beacon set explicitly
3807 * by usermode, don't use the beacon data.
3808 */
3809 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3810 goto end_bcn;
3811
3812 /* remove TIM ie from probe response */
3813 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3814
3815 /*
3816 * remove p2p ie from probe response.
3817 * the fw reponds to probe requests that don't include
3818 * the p2p ie. probe requests with p2p ie will be passed,
3819 * and will be responded by the supplicant (the spec
3820 * forbids including the p2p ie when responding to probe
3821 * requests that didn't include it).
3822 */
3823 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3824 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3825
3826 hdr = (struct ieee80211_hdr *) beacon->data;
3827 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3828 IEEE80211_STYPE_PROBE_RESP);
3829 if (is_ap)
3830 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
3831 beacon->data,
3832 beacon->len,
3833 min_rate);
3834 else
3835 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
3836 CMD_TEMPL_PROBE_RESPONSE,
3837 beacon->data,
3838 beacon->len, 0,
3839 min_rate);
3840end_bcn:
3841 dev_kfree_skb(beacon);
3842 if (ret < 0)
3843 goto out;
3844
3845out:
3846 return ret;
3847}
3848
Arik Nemtsove78a2872010-10-16 19:07:21 +02003849static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3850 struct ieee80211_vif *vif,
3851 struct ieee80211_bss_conf *bss_conf,
3852 u32 changed)
3853{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003854 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003855 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003856 int ret = 0;
3857
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003858 if (changed & BSS_CHANGED_BEACON_INT) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003859 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3860 bss_conf->beacon_int);
3861
Eliad Peller6a899792011-10-05 11:55:58 +02003862 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003863 }
3864
Arik Nemtsov560f002412011-11-08 18:46:54 +02003865 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3866 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003867
3868 wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003869 }
3870
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003871 if (changed & BSS_CHANGED_BEACON) {
Luciano Coelho62c2e572012-05-10 12:14:04 +03003872 ret = wlcore_set_beacon_template(wl, vif, is_ap);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003873 if (ret < 0)
3874 goto out;
3875 }
3876
3877out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003878 if (ret != 0)
3879 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003880 return ret;
3881}
3882
3883/* AP mode changes */
3884static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003885 struct ieee80211_vif *vif,
3886 struct ieee80211_bss_conf *bss_conf,
3887 u32 changed)
3888{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003889 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003890 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003891
Eliad Pellerb6970ee2012-11-20 13:20:05 +02003892 if (changed & BSS_CHANGED_BASIC_RATES) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003893 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003894
Eliad Peller87fbcb02011-10-05 11:55:41 +02003895 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003896 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003897 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003898 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003899
Eliad Peller87fbcb02011-10-05 11:55:41 +02003900 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003901 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003902 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003903 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003904 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003905
Eliad Peller784f6942011-10-05 11:55:39 +02003906 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003907 if (ret < 0)
3908 goto out;
Luciano Coelho62c2e572012-05-10 12:14:04 +03003909
3910 ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
3911 if (ret < 0)
3912 goto out;
3913
3914 ret = wlcore_set_beacon_template(wl, vif, true);
3915 if (ret < 0)
3916 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003917 }
3918
Arik Nemtsove78a2872010-10-16 19:07:21 +02003919 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3920 if (ret < 0)
3921 goto out;
3922
Luciano Coelho48af2eb2012-11-20 11:03:32 +02003923 if (changed & BSS_CHANGED_BEACON_ENABLED) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003924 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003925 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003926 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003927 if (ret < 0)
3928 goto out;
3929
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003930 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003931 if (ret < 0)
3932 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003933
Eliad Peller53d40d02011-10-10 10:13:02 +02003934 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003935 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003936 }
3937 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003938 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003939 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003940 if (ret < 0)
3941 goto out;
3942
Eliad Peller53d40d02011-10-10 10:13:02 +02003943 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003944 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3945 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003946 wl1271_debug(DEBUG_AP, "stopped AP");
3947 }
3948 }
3949 }
3950
Eliad Peller0603d892011-10-05 11:55:51 +02003951 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003952 if (ret < 0)
3953 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003954
3955 /* Handle HT information change */
3956 if ((changed & BSS_CHANGED_HT) &&
Johannes Berg4bf88532012-11-09 11:39:59 +01003957 (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003958 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003959 bss_conf->ht_operation_mode);
3960 if (ret < 0) {
3961 wl1271_warning("Set ht information failed %d", ret);
3962 goto out;
3963 }
3964 }
3965
Arik Nemtsove78a2872010-10-16 19:07:21 +02003966out:
3967 return;
3968}
3969
Eliad Peller3230f352012-11-20 13:20:01 +02003970static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
3971 struct ieee80211_bss_conf *bss_conf,
3972 u32 sta_rate_set)
3973{
3974 u32 rates;
3975 int ret;
3976
3977 wl1271_debug(DEBUG_MAC80211,
3978 "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x",
3979 bss_conf->bssid, bss_conf->aid,
3980 bss_conf->beacon_int,
3981 bss_conf->basic_rates, sta_rate_set);
3982
3983 wlvif->beacon_int = bss_conf->beacon_int;
3984 rates = bss_conf->basic_rates;
3985 wlvif->basic_rate_set =
3986 wl1271_tx_enabled_rates_get(wl, rates,
3987 wlvif->band);
3988 wlvif->basic_rate =
3989 wl1271_tx_min_rate_get(wl,
3990 wlvif->basic_rate_set);
3991
3992 if (sta_rate_set)
3993 wlvif->rate_set =
3994 wl1271_tx_enabled_rates_get(wl,
3995 sta_rate_set,
3996 wlvif->band);
3997
3998 /* we only support sched_scan while not connected */
Eliad Peller10199752012-11-22 18:06:23 +02003999 if (wl->sched_vif == wlvif)
Eliad Peller78e28062012-11-22 18:06:15 +02004000 wl->ops->sched_scan_stop(wl, wlvif);
Eliad Peller3230f352012-11-20 13:20:01 +02004001
4002 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4003 if (ret < 0)
4004 return ret;
4005
4006 ret = wl12xx_cmd_build_null_data(wl, wlvif);
4007 if (ret < 0)
4008 return ret;
4009
4010 ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif));
4011 if (ret < 0)
4012 return ret;
4013
4014 wlcore_set_ssid(wl, wlvif);
4015
4016 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
4017
4018 return 0;
4019}
4020
4021static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4022{
4023 int ret;
4024
4025 /* revert back to minimum rates for the current band */
4026 wl1271_set_band_rate(wl, wlvif);
4027 wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4028
4029 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4030 if (ret < 0)
4031 return ret;
4032
4033 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4034 test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) {
4035 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
4036 if (ret < 0)
4037 return ret;
4038 }
4039
4040 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
4041 return 0;
4042}
Arik Nemtsove78a2872010-10-16 19:07:21 +02004043/* STA/IBSS mode changes */
4044static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
4045 struct ieee80211_vif *vif,
4046 struct ieee80211_bss_conf *bss_conf,
4047 u32 changed)
4048{
Eliad Peller87fbcb02011-10-05 11:55:41 +02004049 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller3230f352012-11-20 13:20:01 +02004050 bool do_join = false;
Eliad Peller536129c2011-10-05 11:55:45 +02004051 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03004052 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004053 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02004054 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01004055 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02004056 bool sta_exists = false;
4057 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02004058
4059 if (is_ibss) {
4060 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
4061 changed);
4062 if (ret < 0)
4063 goto out;
4064 }
4065
Eliad Peller227e81e2011-08-14 13:17:26 +03004066 if (changed & BSS_CHANGED_IBSS) {
4067 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02004068 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03004069 ibss_joined = true;
4070 } else {
Eliad Peller3230f352012-11-20 13:20:01 +02004071 wlcore_unset_assoc(wl, wlvif);
4072 wl12xx_cmd_role_stop_sta(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03004073 }
4074 }
4075
4076 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004077 do_join = true;
4078
4079 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03004080 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004081 do_join = true;
4082
Eliad Peller227e81e2011-08-14 13:17:26 +03004083 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02004084 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
4085 bss_conf->enable_beacon ? "enabled" : "disabled");
4086
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02004087 do_join = true;
4088 }
4089
Luciano Coelho48af2eb2012-11-20 11:03:32 +02004090 if (changed & BSS_CHANGED_CQM) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004091 bool enable = false;
4092 if (bss_conf->cqm_rssi_thold)
4093 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02004094 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004095 bss_conf->cqm_rssi_thold,
4096 bss_conf->cqm_rssi_hyst);
4097 if (ret < 0)
4098 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02004099 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004100 }
4101
Eliad Pellerec870112012-11-20 13:20:09 +02004102 if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT |
4103 BSS_CHANGED_ASSOC)) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004104 rcu_read_lock();
4105 sta = ieee80211_find_sta(vif, bss_conf->bssid);
Luciano Coelhoef08d022012-11-20 11:03:31 +02004106 if (sta) {
4107 u8 *rx_mask = sta->ht_cap.mcs.rx_mask;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004108
Luciano Coelhoef08d022012-11-20 11:03:31 +02004109 /* save the supp_rates of the ap */
4110 sta_rate_set = sta->supp_rates[wlvif->band];
4111 if (sta->ht_cap.ht_supported)
4112 sta_rate_set |=
4113 (rx_mask[0] << HW_HT_RATES_OFFSET) |
4114 (rx_mask[1] << HW_MIMO_RATES_OFFSET);
4115 sta_ht_cap = sta->ht_cap;
4116 sta_exists = true;
4117 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004118
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004119 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004120 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02004121
Eliad Peller3230f352012-11-20 13:20:01 +02004122 if (changed & BSS_CHANGED_BSSID) {
4123 if (!is_zero_ether_addr(bss_conf->bssid)) {
4124 ret = wlcore_set_bssid(wl, wlvif, bss_conf,
4125 sta_rate_set);
4126 if (ret < 0)
4127 goto out;
4128
4129 /* Need to update the BSSID (for filtering etc) */
Eliad Peller446f5ca2012-03-12 14:53:04 +02004130 do_join = true;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03004131 } else {
Eliad Peller3230f352012-11-20 13:20:01 +02004132 ret = wlcore_clear_bssid(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004133 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02004134 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004135 }
4136 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004137
Eliad Pellerd192d262011-05-24 14:33:08 +03004138 if (changed & BSS_CHANGED_IBSS) {
4139 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
4140 bss_conf->ibss_joined);
4141
4142 if (bss_conf->ibss_joined) {
4143 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02004144 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004145 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02004146 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02004147 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02004148 wl1271_tx_min_rate_get(wl,
4149 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03004150
Shahar Levi06b660e2011-09-05 13:54:36 +03004151 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02004152 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
4153 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03004154 if (ret < 0)
4155 goto out;
4156 }
4157 }
4158
Eliad Peller0603d892011-10-05 11:55:51 +02004159 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004160 if (ret < 0)
4161 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004162
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004163 if (do_join) {
Eliad Peller3230f352012-11-20 13:20:01 +02004164 ret = wlcore_join(wl, wlvif);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004165 if (ret < 0) {
4166 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004167 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004168 }
Eliad Peller3230f352012-11-20 13:20:01 +02004169 }
Eliad Peller251c1772011-08-14 13:17:17 +03004170
Eliad Peller3230f352012-11-20 13:20:01 +02004171 if (changed & BSS_CHANGED_ASSOC) {
4172 if (bss_conf->assoc) {
Eliad Pellerec870112012-11-20 13:20:09 +02004173 ret = wlcore_set_assoc(wl, wlvif, bss_conf,
4174 sta_rate_set);
Eliad Peller251c1772011-08-14 13:17:17 +03004175 if (ret < 0)
4176 goto out;
4177
Eliad Peller9fd6f212012-03-04 10:55:48 +02004178 if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
4179 wl12xx_set_authorized(wl, wlvif);
Eliad Peller3230f352012-11-20 13:20:01 +02004180 } else {
4181 wlcore_unset_assoc(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03004182 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02004183 }
4184
Eliad Peller518b6802012-11-26 18:05:47 +02004185 if (changed & BSS_CHANGED_PS) {
4186 if ((bss_conf->ps) &&
4187 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
4188 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
4189 int ps_mode;
4190 char *ps_mode_str;
4191
4192 if (wl->conf.conn.forced_ps) {
4193 ps_mode = STATION_POWER_SAVE_MODE;
4194 ps_mode_str = "forced";
4195 } else {
4196 ps_mode = STATION_AUTO_PS_MODE;
4197 ps_mode_str = "auto";
4198 }
4199
4200 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
4201
4202 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
Kalle Valoc6999d82010-02-18 13:25:41 +02004203 if (ret < 0)
Eliad Peller518b6802012-11-26 18:05:47 +02004204 wl1271_warning("enter %s ps failed %d",
4205 ps_mode_str, ret);
4206 } else if (!bss_conf->ps &&
4207 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
4208 wl1271_debug(DEBUG_PSM, "auto ps disabled");
4209
4210 ret = wl1271_ps_set_mode(wl, wlvif,
4211 STATION_ACTIVE_MODE);
4212 if (ret < 0)
4213 wl1271_warning("exit auto ps failed %d", ret);
Kalle Valoc6999d82010-02-18 13:25:41 +02004214 }
4215 }
Kalle Valo4695dc92010-03-18 12:26:38 +02004216
4217 /* Handle new association with HT. Do this after join. */
Eliad Peller58321b22012-11-20 13:20:10 +02004218 if (sta_exists &&
4219 (changed & BSS_CHANGED_HT)) {
4220 bool enabled =
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004221 bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004222
Eliad Peller530abe12012-11-28 11:42:31 +02004223 ret = wlcore_hw_set_peer_cap(wl,
4224 &sta_ht_cap,
4225 enabled,
4226 wlvif->rate_set,
4227 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004228 if (ret < 0) {
Eliad Peller58321b22012-11-20 13:20:10 +02004229 wl1271_warning("Set ht cap failed %d", ret);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004230 goto out;
Eliad Peller58321b22012-11-20 13:20:10 +02004231
4232 }
4233
4234 if (enabled) {
4235 ret = wl1271_acx_set_ht_information(wl, wlvif,
4236 bss_conf->ht_operation_mode);
4237 if (ret < 0) {
4238 wl1271_warning("Set ht information failed %d",
4239 ret);
4240 goto out;
4241 }
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004242 }
4243 }
4244
Eliad Peller76a74c82012-02-02 12:22:11 +02004245 /* Handle arp filtering. Done after join. */
4246 if ((changed & BSS_CHANGED_ARP_FILTER) ||
4247 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
4248 __be32 addr = bss_conf->arp_addr_list[0];
4249 wlvif->sta.qos = bss_conf->qos;
4250 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
4251
Johannes Berg0f19b412013-01-14 16:39:07 +01004252 if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
Eliad Peller76a74c82012-02-02 12:22:11 +02004253 wlvif->ip_addr = addr;
4254 /*
4255 * The template should have been configured only upon
4256 * association. however, it seems that the correct ip
4257 * isn't being set (when sending), so we have to
4258 * reconfigure the template upon every ip change.
4259 */
4260 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
4261 if (ret < 0) {
4262 wl1271_warning("build arp rsp failed: %d", ret);
4263 goto out;
4264 }
4265
4266 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
4267 (ACX_ARP_FILTER_ARP_FILTERING |
4268 ACX_ARP_FILTER_AUTO_ARP),
4269 addr);
4270 } else {
4271 wlvif->ip_addr = 0;
4272 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
4273 }
4274
4275 if (ret < 0)
4276 goto out;
4277 }
4278
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004279out:
4280 return;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004281}
4282
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004283static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
4284 struct ieee80211_vif *vif,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004285 struct ieee80211_bss_conf *bss_conf,
4286 u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004287{
4288 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004289 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4290 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004291 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004292
Eliad Pellerd3f5a1b2012-11-19 17:14:05 +02004293 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x",
4294 wlvif->role_id, (int)changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004295
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03004296 /*
4297 * make sure to cancel pending disconnections if our association
4298 * state changed
4299 */
4300 if (!is_ap && (changed & BSS_CHANGED_ASSOC))
Eliad Pellerc50a2822012-11-22 18:06:19 +02004301 cancel_delayed_work_sync(&wlvif->connection_loss_work);
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03004302
Eliad Pellerb515d832012-05-15 17:08:56 +03004303 if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
4304 !bss_conf->enable_beacon)
4305 wl1271_tx_flush(wl);
4306
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004307 mutex_lock(&wl->mutex);
4308
Ido Yariv4cc53382012-07-24 19:18:49 +03004309 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004310 goto out;
4311
Eliad Peller10c8cd02011-10-10 10:13:06 +02004312 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
4313 goto out;
4314
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004315 ret = wl1271_ps_elp_wakeup(wl);
4316 if (ret < 0)
4317 goto out;
4318
4319 if (is_ap)
4320 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
4321 else
4322 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
4323
4324 wl1271_ps_elp_sleep(wl);
4325
4326out:
4327 mutex_unlock(&wl->mutex);
4328}
4329
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004330static int wlcore_op_add_chanctx(struct ieee80211_hw *hw,
4331 struct ieee80211_chanctx_conf *ctx)
4332{
4333 wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004334 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4335 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004336 return 0;
4337}
4338
4339static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw,
4340 struct ieee80211_chanctx_conf *ctx)
4341{
4342 wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004343 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4344 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004345}
4346
4347static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
4348 struct ieee80211_chanctx_conf *ctx,
4349 u32 changed)
4350{
4351 wl1271_debug(DEBUG_MAC80211,
4352 "mac80211 change chanctx %d (type %d) changed 0x%x",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004353 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4354 cfg80211_get_chandef_type(&ctx->def), changed);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004355}
4356
4357static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
4358 struct ieee80211_vif *vif,
4359 struct ieee80211_chanctx_conf *ctx)
4360{
4361 struct wl1271 *wl = hw->priv;
4362 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4363 int channel = ieee80211_frequency_to_channel(
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004364 ctx->def.chan->center_freq);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004365
4366 wl1271_debug(DEBUG_MAC80211,
4367 "mac80211 assign chanctx (role %d) %d (type %d)",
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004368 wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004369
4370 mutex_lock(&wl->mutex);
4371
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004372 wlvif->band = ctx->def.chan->band;
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004373 wlvif->channel = channel;
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004374 wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004375
4376 /* update default rates according to the band */
4377 wl1271_set_band_rate(wl, wlvif);
4378
4379 mutex_unlock(&wl->mutex);
4380
4381 return 0;
4382}
4383
4384static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
4385 struct ieee80211_vif *vif,
4386 struct ieee80211_chanctx_conf *ctx)
4387{
4388 struct wl1271 *wl = hw->priv;
4389 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4390
4391 wl1271_debug(DEBUG_MAC80211,
4392 "mac80211 unassign chanctx (role %d) %d (type %d)",
4393 wlvif->role_id,
Luciano Coelhoaaabee82012-12-04 16:39:47 +02004394 ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
4395 cfg80211_get_chandef_type(&ctx->def));
Eliad Pellerb6970ee2012-11-20 13:20:05 +02004396
4397 wl1271_tx_flush(wl);
4398}
4399
Eliad Peller8a3a3c82011-10-02 10:15:52 +02004400static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
4401 struct ieee80211_vif *vif, u16 queue,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402 const struct ieee80211_tx_queue_params *params)
4403{
4404 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004405 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004406 u8 ps_scheme;
4407 int ret = 0;
4408
4409 mutex_lock(&wl->mutex);
4410
4411 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4412
4413 if (params->uapsd)
4414 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4415 else
4416 ps_scheme = CONF_PS_SCHEME_LEGACY;
4417
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004418 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004419 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004420
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004421 ret = wl1271_ps_elp_wakeup(wl);
4422 if (ret < 0)
4423 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004424
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004425 /*
4426 * the txop is confed in units of 32us by the mac80211,
4427 * we need us
4428 */
Eliad Peller0603d892011-10-05 11:55:51 +02004429 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004430 params->cw_min, params->cw_max,
4431 params->aifs, params->txop << 5);
4432 if (ret < 0)
4433 goto out_sleep;
4434
Eliad Peller0603d892011-10-05 11:55:51 +02004435 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004436 CONF_CHANNEL_TYPE_EDCF,
4437 wl1271_tx_get_queue(queue),
4438 ps_scheme, CONF_ACK_POLICY_LEGACY,
4439 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440
4441out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004442 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443
4444out:
4445 mutex_unlock(&wl->mutex);
4446
4447 return ret;
4448}
4449
Eliad Peller37a41b42011-09-21 14:06:11 +03004450static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4451 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452{
4453
4454 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004455 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 u64 mactime = ULLONG_MAX;
4457 int ret;
4458
4459 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4460
4461 mutex_lock(&wl->mutex);
4462
Ido Yariv4cc53382012-07-24 19:18:49 +03004463 if (unlikely(wl->state != WLCORE_STATE_ON))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 goto out;
4465
Ido Yariva6208652011-03-01 15:14:41 +02004466 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 if (ret < 0)
4468 goto out;
4469
Eliad Peller9c531142012-01-31 11:57:18 +02004470 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471 if (ret < 0)
4472 goto out_sleep;
4473
4474out_sleep:
4475 wl1271_ps_elp_sleep(wl);
4476
4477out:
4478 mutex_unlock(&wl->mutex);
4479 return mactime;
4480}
4481
4482static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4483 struct survey_info *survey)
4484{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004485 struct ieee80211_conf *conf = &hw->conf;
4486
4487 if (idx != 0)
4488 return -ENOENT;
4489
Karl Beldan675a0b02013-03-25 16:26:57 +01004490 survey->channel = conf->chandef.chan;
Yoni Divinskyadd779a02012-06-13 18:56:54 +03004491 survey->filled = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004492 return 0;
4493}
4494
Arik Nemtsov409622e2011-02-23 00:22:29 +02004495static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004496 struct wl12xx_vif *wlvif,
4497 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004498{
4499 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004500 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004501
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004502
4503 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004504 wl1271_warning("could not allocate HLID - too much stations");
4505 return -EBUSY;
4506 }
4507
4508 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004509 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4510 if (ret < 0) {
4511 wl1271_warning("could not allocate HLID - too many links");
4512 return -EBUSY;
4513 }
4514
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004515 /* use the previous security seq, if this is a recovery/resume */
4516 wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts;
4517
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004518 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004519 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004520 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004521 return 0;
4522}
4523
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004524void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004525{
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004526 struct wl1271_station *wl_sta;
4527 struct ieee80211_sta *sta;
4528 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4529
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004530 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004531 return;
4532
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004533 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004534 __clear_bit(hlid, &wl->ap_ps_map);
4535 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsov0e752df2013-03-12 17:19:44 +02004536
4537 /*
4538 * save the last used PN in the private part of iee80211_sta,
4539 * in case of recovery/suspend
4540 */
4541 rcu_read_lock();
4542 sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
4543 if (sta) {
4544 wl_sta = (void *)sta->drv_priv;
4545 wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
4546
4547 /*
4548 * increment the initial seq number on recovery to account for
4549 * transmitted packets that we haven't yet got in the FW status
4550 */
4551 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
4552 wl_sta->total_freed_pkts +=
4553 WL1271_TX_SQN_POST_RECOVERY_PADDING;
4554 }
4555 rcu_read_unlock();
4556
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004557 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004558 wl->active_sta_count--;
Arik Nemtsov55df5af2012-03-03 22:18:00 +02004559
4560 /*
4561 * rearm the tx watchdog when the last STA is freed - give the FW a
4562 * chance to return STA-buffered packets before complaining.
4563 */
4564 if (wl->active_sta_count == 0)
4565 wl12xx_rearm_tx_watchdog_locked(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004566}
4567
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004568static int wl12xx_sta_add(struct wl1271 *wl,
4569 struct wl12xx_vif *wlvif,
4570 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004571{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004572 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004573 int ret = 0;
4574 u8 hlid;
4575
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004576 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4577
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004578 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004579 if (ret < 0)
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004580 return ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004581
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004582 wl_sta = (struct wl1271_station *)sta->drv_priv;
4583 hlid = wl_sta->hlid;
4584
Eliad Peller1b92f152011-10-10 10:13:09 +02004585 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004586 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004587 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004588
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004589 return ret;
4590}
4591
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004592static int wl12xx_sta_remove(struct wl1271 *wl,
4593 struct wl12xx_vif *wlvif,
4594 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004595{
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004596 struct wl1271_station *wl_sta;
4597 int ret = 0, id;
4598
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004599 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4600
4601 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004602 id = wl_sta->hlid;
4603 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004604 return -EINVAL;
4605
4606 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
4607 if (ret < 0)
4608 return ret;
4609
4610 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
4611 return ret;
4612}
4613
Eliad Peller426001a2012-11-26 18:05:45 +02004614static void wlcore_roc_if_possible(struct wl1271 *wl,
4615 struct wl12xx_vif *wlvif)
4616{
4617 if (find_first_bit(wl->roc_map,
4618 WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)
4619 return;
4620
4621 if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID))
4622 return;
4623
4624 wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
4625}
4626
4627static void wlcore_update_inconn_sta(struct wl1271 *wl,
4628 struct wl12xx_vif *wlvif,
4629 struct wl1271_station *wl_sta,
4630 bool in_connection)
4631{
4632 if (in_connection) {
4633 if (WARN_ON(wl_sta->in_connection))
4634 return;
4635 wl_sta->in_connection = true;
4636 if (!wlvif->inconn_count++)
4637 wlcore_roc_if_possible(wl, wlvif);
4638 } else {
4639 if (!wl_sta->in_connection)
4640 return;
4641
4642 wl_sta->in_connection = false;
4643 wlvif->inconn_count--;
4644 if (WARN_ON(wlvif->inconn_count < 0))
4645 return;
4646
4647 if (!wlvif->inconn_count)
4648 if (test_bit(wlvif->role_id, wl->roc_map))
4649 wl12xx_croc(wl, wlvif->role_id);
4650 }
4651}
4652
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004653static int wl12xx_update_sta_state(struct wl1271 *wl,
4654 struct wl12xx_vif *wlvif,
4655 struct ieee80211_sta *sta,
4656 enum ieee80211_sta_state old_state,
4657 enum ieee80211_sta_state new_state)
4658{
4659 struct wl1271_station *wl_sta;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004660 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
4661 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
4662 int ret;
4663
4664 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004665
4666 /* Add station (AP mode) */
4667 if (is_ap &&
4668 old_state == IEEE80211_STA_NOTEXIST &&
Eliad Peller29936262012-11-20 13:20:06 +02004669 new_state == IEEE80211_STA_NONE) {
4670 ret = wl12xx_sta_add(wl, wlvif, sta);
4671 if (ret)
4672 return ret;
Eliad Peller426001a2012-11-26 18:05:45 +02004673
4674 wlcore_update_inconn_sta(wl, wlvif, wl_sta, true);
Eliad Peller29936262012-11-20 13:20:06 +02004675 }
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004676
4677 /* Remove station (AP mode) */
4678 if (is_ap &&
4679 old_state == IEEE80211_STA_NONE &&
4680 new_state == IEEE80211_STA_NOTEXIST) {
4681 /* must not fail */
4682 wl12xx_sta_remove(wl, wlvif, sta);
Eliad Peller426001a2012-11-26 18:05:45 +02004683
4684 wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004685 }
4686
4687 /* Authorize station (AP mode) */
4688 if (is_ap &&
4689 new_state == IEEE80211_STA_AUTHORIZED) {
Arik Nemtsov2fec3d22013-03-12 17:19:37 +02004690 ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004691 if (ret < 0)
4692 return ret;
4693
4694 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
Arik Nemtsov2fec3d22013-03-12 17:19:37 +02004695 wl_sta->hlid);
Eliad Peller29936262012-11-20 13:20:06 +02004696 if (ret)
4697 return ret;
Eliad Peller426001a2012-11-26 18:05:45 +02004698
4699 wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004700 }
4701
Eliad Peller9fd6f212012-03-04 10:55:48 +02004702 /* Authorize station */
4703 if (is_sta &&
4704 new_state == IEEE80211_STA_AUTHORIZED) {
4705 set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
Eliad Peller29936262012-11-20 13:20:06 +02004706 ret = wl12xx_set_authorized(wl, wlvif);
4707 if (ret)
4708 return ret;
Eliad Peller9fd6f212012-03-04 10:55:48 +02004709 }
4710
4711 if (is_sta &&
4712 old_state == IEEE80211_STA_AUTHORIZED &&
4713 new_state == IEEE80211_STA_ASSOC) {
4714 clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
Eliad Peller3230f352012-11-20 13:20:01 +02004715 clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags);
Eliad Peller9fd6f212012-03-04 10:55:48 +02004716 }
4717
Eliad Peller29936262012-11-20 13:20:06 +02004718 /* clear ROCs on failure or authorization */
4719 if (is_sta &&
4720 (new_state == IEEE80211_STA_AUTHORIZED ||
4721 new_state == IEEE80211_STA_NOTEXIST)) {
4722 if (test_bit(wlvif->role_id, wl->roc_map))
4723 wl12xx_croc(wl, wlvif->role_id);
4724 }
4725
4726 if (is_sta &&
4727 old_state == IEEE80211_STA_NOTEXIST &&
4728 new_state == IEEE80211_STA_NONE) {
4729 if (find_first_bit(wl->roc_map,
4730 WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) {
4731 WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID);
4732 wl12xx_roc(wl, wlvif, wlvif->role_id,
4733 wlvif->band, wlvif->channel);
4734 }
4735 }
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004736 return 0;
4737}
4738
4739static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
4740 struct ieee80211_vif *vif,
4741 struct ieee80211_sta *sta,
4742 enum ieee80211_sta_state old_state,
4743 enum ieee80211_sta_state new_state)
4744{
4745 struct wl1271 *wl = hw->priv;
4746 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4747 int ret;
4748
4749 wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
4750 sta->aid, old_state, new_state);
4751
4752 mutex_lock(&wl->mutex);
4753
Ido Yariv4cc53382012-07-24 19:18:49 +03004754 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004755 ret = -EBUSY;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004756 goto out;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004757 }
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004758
Ido Yariva6208652011-03-01 15:14:41 +02004759 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004760 if (ret < 0)
4761 goto out;
4762
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004763 ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004764
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004765 wl1271_ps_elp_sleep(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004766out:
4767 mutex_unlock(&wl->mutex);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004768 if (new_state < old_state)
4769 return 0;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004770 return ret;
4771}
4772
Luciano Coelho4623ec72011-03-21 19:26:41 +02004773static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4774 struct ieee80211_vif *vif,
4775 enum ieee80211_ampdu_mlme_action action,
4776 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4777 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004778{
4779 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004780 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004781 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004782 u8 hlid, *ba_bitmap;
4783
4784 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4785 tid);
4786
4787 /* sanity check - the fields in FW are only 8bits wide */
4788 if (WARN_ON(tid > 0xFF))
4789 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004790
4791 mutex_lock(&wl->mutex);
4792
Ido Yariv4cc53382012-07-24 19:18:49 +03004793 if (unlikely(wl->state != WLCORE_STATE_ON)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004794 ret = -EAGAIN;
4795 goto out;
4796 }
4797
Eliad Peller536129c2011-10-05 11:55:45 +02004798 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004799 hlid = wlvif->sta.hlid;
Eliad Peller536129c2011-10-05 11:55:45 +02004800 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004801 struct wl1271_station *wl_sta;
4802
4803 wl_sta = (struct wl1271_station *)sta->drv_priv;
4804 hlid = wl_sta->hlid;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004805 } else {
4806 ret = -EINVAL;
4807 goto out;
4808 }
4809
Arik Nemtsov9ae5d8d2012-11-28 11:42:45 +02004810 ba_bitmap = &wl->links[hlid].ba_bitmap;
4811
Ido Yariva6208652011-03-01 15:14:41 +02004812 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004813 if (ret < 0)
4814 goto out;
4815
Shahar Levi70559a02011-05-22 16:10:22 +03004816 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4817 tid, action);
4818
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004819 switch (action) {
4820 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004821 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004822 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004823 break;
4824 }
4825
Igal Chernobelskyd21553f2013-03-12 17:19:35 +02004826 if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004827 ret = -EBUSY;
4828 wl1271_error("exceeded max RX BA sessions");
4829 break;
4830 }
4831
4832 if (*ba_bitmap & BIT(tid)) {
4833 ret = -EINVAL;
4834 wl1271_error("cannot enable RX BA session on active "
4835 "tid: %d", tid);
4836 break;
4837 }
4838
4839 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4840 hlid);
4841 if (!ret) {
4842 *ba_bitmap |= BIT(tid);
4843 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004844 }
4845 break;
4846
4847 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004848 if (!(*ba_bitmap & BIT(tid))) {
Arik Nemtsovc9549102012-06-06 10:48:56 +03004849 /*
4850 * this happens on reconfig - so only output a debug
4851 * message for now, and don't fail the function.
4852 */
4853 wl1271_debug(DEBUG_MAC80211,
4854 "no active RX BA session on tid: %d",
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004855 tid);
Arik Nemtsovc9549102012-06-06 10:48:56 +03004856 ret = 0;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004857 break;
4858 }
4859
4860 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4861 hlid);
4862 if (!ret) {
4863 *ba_bitmap &= ~BIT(tid);
4864 wl->ba_rx_session_count--;
4865 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004866 break;
4867
4868 /*
4869 * The BA initiator session management in FW independently.
4870 * Falling break here on purpose for all TX APDU commands.
4871 */
4872 case IEEE80211_AMPDU_TX_START:
Johannes Berg18b559d2012-07-18 13:51:25 +02004873 case IEEE80211_AMPDU_TX_STOP_CONT:
4874 case IEEE80211_AMPDU_TX_STOP_FLUSH:
4875 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004876 case IEEE80211_AMPDU_TX_OPERATIONAL:
4877 ret = -EINVAL;
4878 break;
4879
4880 default:
4881 wl1271_error("Incorrect ampdu action id=%x\n", action);
4882 ret = -EINVAL;
4883 }
4884
4885 wl1271_ps_elp_sleep(wl);
4886
4887out:
4888 mutex_unlock(&wl->mutex);
4889
4890 return ret;
4891}
4892
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004893static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4894 struct ieee80211_vif *vif,
4895 const struct cfg80211_bitrate_mask *mask)
4896{
Eliad Peller83587502011-10-10 10:12:53 +02004897 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004898 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004899 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004900
4901 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4902 mask->control[NL80211_BAND_2GHZ].legacy,
4903 mask->control[NL80211_BAND_5GHZ].legacy);
4904
4905 mutex_lock(&wl->mutex);
4906
Arik Nemtsov091185d2012-07-03 09:11:03 +03004907 for (i = 0; i < WLCORE_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004908 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004909 wl1271_tx_enabled_rates_get(wl,
4910 mask->control[i].legacy,
4911 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004912
Ido Yariv4cc53382012-07-24 19:18:49 +03004913 if (unlikely(wl->state != WLCORE_STATE_ON))
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004914 goto out;
4915
4916 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4917 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4918
4919 ret = wl1271_ps_elp_wakeup(wl);
4920 if (ret < 0)
4921 goto out;
4922
4923 wl1271_set_band_rate(wl, wlvif);
4924 wlvif->basic_rate =
4925 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4926 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4927
4928 wl1271_ps_elp_sleep(wl);
4929 }
4930out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004931 mutex_unlock(&wl->mutex);
4932
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004933 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004934}
4935
Shahar Levi6d158ff2011-09-08 13:01:33 +03004936static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4937 struct ieee80211_channel_switch *ch_switch)
4938{
4939 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004940 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004941 int ret;
4942
4943 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4944
Arik Nemtsovb9239b62012-02-28 00:41:33 +02004945 wl1271_tx_flush(wl);
4946
Shahar Levi6d158ff2011-09-08 13:01:33 +03004947 mutex_lock(&wl->mutex);
4948
Ido Yariv4cc53382012-07-24 19:18:49 +03004949 if (unlikely(wl->state == WLCORE_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004950 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4951 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4952 ieee80211_chswitch_done(vif, false);
4953 }
4954 goto out;
Ido Yariv4cc53382012-07-24 19:18:49 +03004955 } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
4956 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004957 }
4958
4959 ret = wl1271_ps_elp_wakeup(wl);
4960 if (ret < 0)
4961 goto out;
4962
Eliad Peller52630c52011-10-10 10:13:08 +02004963 /* TODO: change mac80211 to pass vif as param */
4964 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Pellerc50a2822012-11-22 18:06:19 +02004965 unsigned long delay_usec;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004966
Eliad Pellerfcab1892012-11-22 18:06:18 +02004967 ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
Eliad Pellerc50a2822012-11-22 18:06:19 +02004968 if (ret)
4969 goto out_sleep;
4970
4971 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4972
4973 /* indicate failure 5 seconds after channel switch time */
4974 delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
4975 ch_switch->count;
4976 ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
4977 usecs_to_jiffies(delay_usec) +
4978 msecs_to_jiffies(5000));
Eliad Peller52630c52011-10-10 10:13:08 +02004979 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004980
Eliad Pellerc50a2822012-11-22 18:06:19 +02004981out_sleep:
Shahar Levi6d158ff2011-09-08 13:01:33 +03004982 wl1271_ps_elp_sleep(wl);
4983
4984out:
4985 mutex_unlock(&wl->mutex);
4986}
4987
Johannes Berg39ecc012013-02-13 12:11:00 +01004988static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
Eliad Pellerd8ae5a22012-06-25 13:52:33 +03004989{
4990 struct wl1271 *wl = hw->priv;
4991
4992 wl1271_tx_flush(wl);
4993}
4994
Eliad Pellerdabf37d2012-11-20 13:20:03 +02004995static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
4996 struct ieee80211_vif *vif,
4997 struct ieee80211_channel *chan,
Ilan Peerd339d5c2013-02-12 09:34:13 +02004998 int duration,
4999 enum ieee80211_roc_type type)
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005000{
5001 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5002 struct wl1271 *wl = hw->priv;
5003 int channel, ret = 0;
5004
5005 channel = ieee80211_frequency_to_channel(chan->center_freq);
5006
5007 wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)",
5008 channel, wlvif->role_id);
5009
5010 mutex_lock(&wl->mutex);
5011
5012 if (unlikely(wl->state != WLCORE_STATE_ON))
5013 goto out;
5014
5015 /* return EBUSY if we can't ROC right now */
5016 if (WARN_ON(wl->roc_vif ||
5017 find_first_bit(wl->roc_map,
5018 WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) {
5019 ret = -EBUSY;
5020 goto out;
5021 }
5022
5023 ret = wl1271_ps_elp_wakeup(wl);
5024 if (ret < 0)
5025 goto out;
5026
5027 ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
5028 if (ret < 0)
5029 goto out_sleep;
5030
5031 wl->roc_vif = vif;
5032 ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
5033 msecs_to_jiffies(duration));
5034out_sleep:
5035 wl1271_ps_elp_sleep(wl);
5036out:
5037 mutex_unlock(&wl->mutex);
5038 return ret;
5039}
5040
5041static int __wlcore_roc_completed(struct wl1271 *wl)
5042{
5043 struct wl12xx_vif *wlvif;
5044 int ret;
5045
5046 /* already completed */
5047 if (unlikely(!wl->roc_vif))
5048 return 0;
5049
5050 wlvif = wl12xx_vif_to_data(wl->roc_vif);
5051
5052 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
5053 return -EBUSY;
5054
5055 ret = wl12xx_stop_dev(wl, wlvif);
5056 if (ret < 0)
5057 return ret;
5058
5059 wl->roc_vif = NULL;
5060
5061 return 0;
5062}
5063
5064static int wlcore_roc_completed(struct wl1271 *wl)
5065{
5066 int ret;
5067
5068 wl1271_debug(DEBUG_MAC80211, "roc complete");
5069
5070 mutex_lock(&wl->mutex);
5071
5072 if (unlikely(wl->state != WLCORE_STATE_ON)) {
5073 ret = -EBUSY;
5074 goto out;
5075 }
5076
5077 ret = wl1271_ps_elp_wakeup(wl);
5078 if (ret < 0)
5079 goto out;
5080
5081 ret = __wlcore_roc_completed(wl);
5082
5083 wl1271_ps_elp_sleep(wl);
5084out:
5085 mutex_unlock(&wl->mutex);
5086
5087 return ret;
5088}
5089
5090static void wlcore_roc_complete_work(struct work_struct *work)
5091{
5092 struct delayed_work *dwork;
5093 struct wl1271 *wl;
5094 int ret;
5095
5096 dwork = container_of(work, struct delayed_work, work);
5097 wl = container_of(dwork, struct wl1271, roc_complete_work);
5098
5099 ret = wlcore_roc_completed(wl);
5100 if (!ret)
5101 ieee80211_remain_on_channel_expired(wl->hw);
5102}
5103
5104static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
5105{
5106 struct wl1271 *wl = hw->priv;
5107
5108 wl1271_debug(DEBUG_MAC80211, "mac80211 croc");
5109
5110 /* TODO: per-vif */
5111 wl1271_tx_flush(wl);
5112
5113 /*
5114 * we can't just flush_work here, because it might deadlock
5115 * (as we might get called from the same workqueue)
5116 */
5117 cancel_delayed_work_sync(&wl->roc_complete_work);
5118 wlcore_roc_completed(wl);
5119
5120 return 0;
5121}
5122
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02005123static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
5124 struct ieee80211_vif *vif,
5125 struct ieee80211_sta *sta,
5126 u32 changed)
5127{
5128 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5129 struct wl1271 *wl = hw->priv;
5130
5131 wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
5132}
5133
Nadim Zubidat0a9ffac2013-03-12 17:19:39 +02005134static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
5135 struct ieee80211_vif *vif,
5136 struct ieee80211_sta *sta,
5137 s8 *rssi_dbm)
5138{
5139 struct wl1271 *wl = hw->priv;
5140 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5141 int ret = 0;
5142
5143 wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
5144
5145 mutex_lock(&wl->mutex);
5146
5147 if (unlikely(wl->state != WLCORE_STATE_ON))
5148 goto out;
5149
5150 ret = wl1271_ps_elp_wakeup(wl);
5151 if (ret < 0)
5152 goto out_sleep;
5153
5154 ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
5155 if (ret < 0)
5156 goto out_sleep;
5157
5158out_sleep:
5159 wl1271_ps_elp_sleep(wl);
5160
5161out:
5162 mutex_unlock(&wl->mutex);
5163
5164 return ret;
5165}
5166
Arik Nemtsov33437892011-04-26 23:35:39 +03005167static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
5168{
5169 struct wl1271 *wl = hw->priv;
5170 bool ret = false;
5171
5172 mutex_lock(&wl->mutex);
5173
Ido Yariv4cc53382012-07-24 19:18:49 +03005174 if (unlikely(wl->state != WLCORE_STATE_ON))
Arik Nemtsov33437892011-04-26 23:35:39 +03005175 goto out;
5176
5177 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03005178 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03005179out:
5180 mutex_unlock(&wl->mutex);
5181
5182 return ret;
5183}
5184
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005185/* can't be const, mac80211 writes to this */
5186static struct ieee80211_rate wl1271_rates[] = {
5187 { .bitrate = 10,
5188 .hw_value = CONF_HW_BIT_RATE_1MBPS,
5189 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
5190 { .bitrate = 20,
5191 .hw_value = CONF_HW_BIT_RATE_2MBPS,
5192 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
5193 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5194 { .bitrate = 55,
5195 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
5196 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
5197 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5198 { .bitrate = 110,
5199 .hw_value = CONF_HW_BIT_RATE_11MBPS,
5200 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
5201 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
5202 { .bitrate = 60,
5203 .hw_value = CONF_HW_BIT_RATE_6MBPS,
5204 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
5205 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005206 .hw_value = CONF_HW_BIT_RATE_9MBPS,
5207 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005208 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005209 .hw_value = CONF_HW_BIT_RATE_12MBPS,
5210 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005211 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005212 .hw_value = CONF_HW_BIT_RATE_18MBPS,
5213 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005214 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005215 .hw_value = CONF_HW_BIT_RATE_24MBPS,
5216 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005217 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005218 .hw_value = CONF_HW_BIT_RATE_36MBPS,
5219 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005220 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005221 .hw_value = CONF_HW_BIT_RATE_48MBPS,
5222 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005223 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03005224 .hw_value = CONF_HW_BIT_RATE_54MBPS,
5225 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005226};
5227
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01005228/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005229static struct ieee80211_channel wl1271_channels[] = {
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005230 { .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR },
5231 { .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR },
5232 { .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR },
5233 { .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR },
5234 { .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR },
5235 { .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR },
5236 { .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR },
5237 { .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR },
5238 { .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR },
5239 { .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR },
5240 { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR },
5241 { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR },
5242 { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR },
5243 { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005244};
5245
5246/* can't be const, mac80211 writes to this */
5247static struct ieee80211_supported_band wl1271_band_2ghz = {
5248 .channels = wl1271_channels,
5249 .n_channels = ARRAY_SIZE(wl1271_channels),
5250 .bitrates = wl1271_rates,
5251 .n_bitrates = ARRAY_SIZE(wl1271_rates),
5252};
5253
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005254/* 5 GHz data rates for WL1273 */
5255static struct ieee80211_rate wl1271_rates_5ghz[] = {
5256 { .bitrate = 60,
5257 .hw_value = CONF_HW_BIT_RATE_6MBPS,
5258 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
5259 { .bitrate = 90,
5260 .hw_value = CONF_HW_BIT_RATE_9MBPS,
5261 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
5262 { .bitrate = 120,
5263 .hw_value = CONF_HW_BIT_RATE_12MBPS,
5264 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
5265 { .bitrate = 180,
5266 .hw_value = CONF_HW_BIT_RATE_18MBPS,
5267 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
5268 { .bitrate = 240,
5269 .hw_value = CONF_HW_BIT_RATE_24MBPS,
5270 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
5271 { .bitrate = 360,
5272 .hw_value = CONF_HW_BIT_RATE_36MBPS,
5273 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
5274 { .bitrate = 480,
5275 .hw_value = CONF_HW_BIT_RATE_48MBPS,
5276 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
5277 { .bitrate = 540,
5278 .hw_value = CONF_HW_BIT_RATE_54MBPS,
5279 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
5280};
5281
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01005282/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005283static struct ieee80211_channel wl1271_channels_5ghz[] = {
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005284 { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
5285 { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
5286 { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
5287 { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
5288 { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
5289 { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
5290 { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
5291 { .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR },
5292 { .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR },
5293 { .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR },
5294 { .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR },
5295 { .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR },
5296 { .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR },
5297 { .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR },
5298 { .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR },
5299 { .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR },
5300 { .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR },
5301 { .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR },
5302 { .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR },
5303 { .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR },
5304 { .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR },
5305 { .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR },
5306 { .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR },
5307 { .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR },
5308 { .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR },
5309 { .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR },
5310 { .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR },
5311 { .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR },
5312 { .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR },
5313 { .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR },
5314 { .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR },
5315 { .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR },
5316 { .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR },
5317 { .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005318};
5319
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005320static struct ieee80211_supported_band wl1271_band_5ghz = {
5321 .channels = wl1271_channels_5ghz,
5322 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
5323 .bitrates = wl1271_rates_5ghz,
5324 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005325};
5326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005327static const struct ieee80211_ops wl1271_ops = {
5328 .start = wl1271_op_start,
Ido Yarivc24ec832012-06-26 21:08:58 +03005329 .stop = wlcore_op_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005330 .add_interface = wl1271_op_add_interface,
5331 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02005332 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04005333#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03005334 .suspend = wl1271_op_suspend,
5335 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04005336#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005337 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03005338 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005339 .configure_filter = wl1271_op_configure_filter,
5340 .tx = wl1271_op_tx,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03005341 .set_key = wlcore_op_set_key,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005342 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03005343 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03005344 .sched_scan_start = wl1271_op_sched_scan_start,
5345 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005346 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01005347 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005348 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02005349 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03005350 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04005351 .get_survey = wl1271_op_get_survey,
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02005352 .sta_state = wl12xx_op_sta_state,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01005353 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03005354 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03005355 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03005356 .channel_switch = wl12xx_op_channel_switch,
Eliad Pellerd8ae5a22012-06-25 13:52:33 +03005357 .flush = wlcore_op_flush,
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005358 .remain_on_channel = wlcore_op_remain_on_channel,
5359 .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
Eliad Pellerb6970ee2012-11-20 13:20:05 +02005360 .add_chanctx = wlcore_op_add_chanctx,
5361 .remove_chanctx = wlcore_op_remove_chanctx,
5362 .change_chanctx = wlcore_op_change_chanctx,
5363 .assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
5364 .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02005365 .sta_rc_update = wlcore_op_sta_rc_update,
Nadim Zubidat0a9ffac2013-03-12 17:19:39 +02005366 .get_rssi = wlcore_op_get_rssi,
Kalle Valoc8c90872010-02-18 13:25:53 +02005367 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005368};
5369
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005370
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005371u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005372{
5373 u8 idx;
5374
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005375 BUG_ON(band >= 2);
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005376
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005377 if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005378 wl1271_error("Illegal RX rate from HW: %d", rate);
5379 return 0;
5380 }
5381
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02005382 idx = wl->band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02005383 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
5384 wl1271_error("Unsupported RX rate from HW: %d", rate);
5385 return 0;
5386 }
5387
5388 return idx;
5389}
5390
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005391static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
Luciano Coelho5e037e72011-12-23 09:32:17 +02005392{
5393 int i;
5394
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005395 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x",
5396 oui, nic);
Luciano Coelho5e037e72011-12-23 09:32:17 +02005397
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005398 if (nic + WLCORE_NUM_MAC_ADDRESSES - wl->num_mac_addr > 0xffffff)
Luciano Coelho5e037e72011-12-23 09:32:17 +02005399 wl1271_warning("NIC part of the MAC address wraps around!");
5400
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005401 for (i = 0; i < wl->num_mac_addr; i++) {
Luciano Coelho5e037e72011-12-23 09:32:17 +02005402 wl->addresses[i].addr[0] = (u8)(oui >> 16);
5403 wl->addresses[i].addr[1] = (u8)(oui >> 8);
5404 wl->addresses[i].addr[2] = (u8) oui;
5405 wl->addresses[i].addr[3] = (u8)(nic >> 16);
5406 wl->addresses[i].addr[4] = (u8)(nic >> 8);
5407 wl->addresses[i].addr[5] = (u8) nic;
5408 nic++;
5409 }
5410
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005411 /* we may be one address short at the most */
5412 WARN_ON(wl->num_mac_addr + 1 < WLCORE_NUM_MAC_ADDRESSES);
5413
5414 /*
5415 * turn on the LAA bit in the first address and use it as
5416 * the last address.
5417 */
5418 if (wl->num_mac_addr < WLCORE_NUM_MAC_ADDRESSES) {
5419 int idx = WLCORE_NUM_MAC_ADDRESSES - 1;
5420 memcpy(&wl->addresses[idx], &wl->addresses[0],
5421 sizeof(wl->addresses[0]));
5422 /* LAA bit */
5423 wl->addresses[idx].addr[2] |= BIT(1);
5424 }
5425
5426 wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES;
Luciano Coelho5e037e72011-12-23 09:32:17 +02005427 wl->hw->wiphy->addresses = wl->addresses;
5428}
5429
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005430static int wl12xx_get_hw_info(struct wl1271 *wl)
5431{
5432 int ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005433
5434 ret = wl12xx_set_power_on(wl);
5435 if (ret < 0)
Julia Lawall4fb4e0b2012-10-21 12:52:04 +02005436 return ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005437
Ido Yariv61343232012-06-18 15:50:21 +03005438 ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
5439 if (ret < 0)
5440 goto out;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005441
Luciano Coelho00782132011-11-29 13:38:37 +02005442 wl->fuse_oui_addr = 0;
5443 wl->fuse_nic_addr = 0;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005444
Ido Yariv61343232012-06-18 15:50:21 +03005445 ret = wl->ops->get_pg_ver(wl, &wl->hw_pg_ver);
5446 if (ret < 0)
5447 goto out;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005448
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03005449 if (wl->ops->get_mac)
Ido Yariv61343232012-06-18 15:50:21 +03005450 ret = wl->ops->get_mac(wl);
Luciano Coelho5e037e72011-12-23 09:32:17 +02005451
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005452out:
Ido Yariv61343232012-06-18 15:50:21 +03005453 wl1271_power_off(wl);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005454 return ret;
5455}
5456
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005457static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005458{
5459 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02005460 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005461
5462 if (wl->mac80211_registered)
5463 return 0;
5464
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005465 if (wl->nvs_len >= 12) {
Shahar Levibc765bf2011-03-06 16:32:10 +02005466 /* NOTE: The wl->nvs->nvs element must be first, in
5467 * order to simplify the casting, we assume it is at
5468 * the beginning of the wl->nvs structure.
5469 */
5470 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005471
Luciano Coelho5e037e72011-12-23 09:32:17 +02005472 oui_addr =
5473 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
5474 nic_addr =
5475 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005476 }
5477
Luciano Coelho5e037e72011-12-23 09:32:17 +02005478 /* if the MAC address is zeroed in the NVS derive from fuse */
5479 if (oui_addr == 0 && nic_addr == 0) {
5480 oui_addr = wl->fuse_oui_addr;
5481 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
5482 nic_addr = wl->fuse_nic_addr + 1;
5483 }
5484
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03005485 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005486
5487 ret = ieee80211_register_hw(wl->hw);
5488 if (ret < 0) {
5489 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005490 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005491 }
5492
5493 wl->mac80211_registered = true;
5494
Eliad Pellerd60080a2010-11-24 12:53:16 +02005495 wl1271_debugfs_init(wl);
5496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005497 wl1271_notice("loaded");
5498
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005499out:
5500 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005501}
5502
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005503static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005504{
Eliad Peller3fcdab72012-02-06 12:47:54 +02005505 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02005506 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005507
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005508 ieee80211_unregister_hw(wl->hw);
5509 wl->mac80211_registered = false;
5510
5511}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005512
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005513static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
5514 {
Arik Nemtsove7a6ba292012-08-02 22:00:34 +03005515 .max = 3,
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005516 .types = BIT(NL80211_IFTYPE_STATION),
5517 },
5518 {
5519 .max = 1,
5520 .types = BIT(NL80211_IFTYPE_AP) |
5521 BIT(NL80211_IFTYPE_P2P_GO) |
5522 BIT(NL80211_IFTYPE_P2P_CLIENT),
5523 },
5524};
5525
Arik Nemtsovde407502012-11-26 18:05:44 +02005526static struct ieee80211_iface_combination
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005527wlcore_iface_combinations[] = {
5528 {
Arik Nemtsove7a6ba292012-08-02 22:00:34 +03005529 .max_interfaces = 3,
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005530 .limits = wlcore_iface_limits,
5531 .n_limits = ARRAY_SIZE(wlcore_iface_limits),
5532 },
5533};
5534
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005535static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005536{
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005537 int i;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005538 static const u32 cipher_suites[] = {
5539 WLAN_CIPHER_SUITE_WEP40,
5540 WLAN_CIPHER_SUITE_WEP104,
5541 WLAN_CIPHER_SUITE_TKIP,
5542 WLAN_CIPHER_SUITE_CCMP,
5543 WL1271_CIPHER_SUITE_GEM,
5544 };
5545
Arik Nemtsov2c0133a2012-05-18 07:46:36 +03005546 /* The tx descriptor buffer */
5547 wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
5548
5549 if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
5550 wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005551
5552 /* unit us */
5553 /* FIXME: find a proper value */
5554 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005555 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005556
5557 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005558 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005559 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005560 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005561 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005562 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005563 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005564 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005565 IEEE80211_HW_AP_LINK_PS |
5566 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005567 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
Arik Nemtsov1c33db72012-11-30 00:48:03 +02005568 IEEE80211_HW_QUEUE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005569
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005570 wl->hw->wiphy->cipher_suites = cipher_suites;
5571 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5572
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005573 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005574 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5575 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005576 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005577 wl->hw->wiphy->max_sched_scan_ssids = 16;
5578 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005579 /*
5580 * Maximum length of elements in scanning probe request templates
5581 * should be the maximum length possible for a template, without
5582 * the IEEE80211 header of the template
5583 */
Ido Reisc08e3712012-02-02 13:54:27 +02005584 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005585 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005586
Ido Reisc08e3712012-02-02 13:54:27 +02005587 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005588 sizeof(struct ieee80211_header);
5589
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005590 wl->hw->wiphy->max_remain_on_channel_duration = 5000;
5591
Johannes Berg81ddbb52012-03-26 18:47:18 +02005592 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
5593 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
Eliad Peller1ec23f72011-08-25 14:26:54 +03005594
Luciano Coelho4a31c112011-03-21 23:16:14 +02005595 /* make sure all our channels fit in the scanned_ch bitmask */
5596 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5597 ARRAY_SIZE(wl1271_channels_5ghz) >
5598 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005599 /*
Victor Goldenshtein583f8162012-11-27 08:44:55 +02005600 * clear channel flags from the previous usage
5601 * and restore max_power & max_antenna_gain values.
5602 */
5603 for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) {
5604 wl1271_band_2ghz.channels[i].flags = 0;
5605 wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
5606 wl1271_band_2ghz.channels[i].max_antenna_gain = 0;
5607 }
5608
5609 for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) {
5610 wl1271_band_5ghz.channels[i].flags = 0;
5611 wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
5612 wl1271_band_5ghz.channels[i].max_antenna_gain = 0;
5613 }
5614
5615 /*
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005616 * We keep local copies of the band structs because we need to
5617 * modify them on a per-device basis.
5618 */
5619 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5620 sizeof(wl1271_band_2ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005621 memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
5622 &wl->ht_cap[IEEE80211_BAND_2GHZ],
5623 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005624 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5625 sizeof(wl1271_band_5ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005626 memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
5627 &wl->ht_cap[IEEE80211_BAND_5GHZ],
5628 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005629
5630 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5631 &wl->bands[IEEE80211_BAND_2GHZ];
5632 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5633 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005634
Arik Nemtsov1c33db72012-11-30 00:48:03 +02005635 /*
5636 * allow 4 queues per mac address we support +
5637 * 1 cab queue per mac + one global offchannel Tx queue
5638 */
5639 wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1;
5640
5641 /* the last queue is the offchannel queue */
5642 wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005643 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005644
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005645 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5646
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005647 /* the FW answers probe-requests in AP-mode */
5648 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5649 wl->hw->wiphy->probe_resp_offload =
5650 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5651 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5652 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5653
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005654 /* allowed interface combinations */
Arik Nemtsovde407502012-11-26 18:05:44 +02005655 wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005656 wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
5657 wl->hw->wiphy->n_iface_combinations =
5658 ARRAY_SIZE(wlcore_iface_combinations);
5659
Felipe Balbia390e852011-10-06 10:07:44 +03005660 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005661
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005662 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005663 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005664
Arik Nemtsovba421f82012-01-06 00:05:51 +02005665 wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size;
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005667 return 0;
5668}
5669
Eliad Pellerc50a2822012-11-22 18:06:19 +02005670struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
5671 u32 mbox_size)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005672{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005673 struct ieee80211_hw *hw;
5674 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005675 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005676 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005677
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005678 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005679
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005680 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5681 if (!hw) {
5682 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005683 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005684 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005685 }
5686
5687 wl = hw->priv;
5688 memset(wl, 0, sizeof(*wl));
5689
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005690 wl->priv = kzalloc(priv_size, GFP_KERNEL);
5691 if (!wl->priv) {
5692 wl1271_error("could not alloc wl priv");
5693 ret = -ENOMEM;
5694 goto err_priv_alloc;
5695 }
5696
Eliad Peller87627212011-10-10 10:12:54 +02005697 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005698
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005699 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005700
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005701 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005702 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005703 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5704
Ido Yariva6208652011-03-01 15:14:41 +02005705 skb_queue_head_init(&wl->deferred_rx_queue);
5706 skb_queue_head_init(&wl->deferred_tx_queue);
5707
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005708 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005709 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005710 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5711 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5712 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Pellerdabf37d2012-11-20 13:20:03 +02005713 INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02005714 INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005715
Eliad Peller92ef8962011-06-07 12:50:46 +03005716 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5717 if (!wl->freezable_wq) {
5718 ret = -ENOMEM;
5719 goto err_hw;
5720 }
5721
Luciano Coelho8f6ac532013-05-04 01:06:11 +03005722 wl->channel = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005723 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005724 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005725 wl->band = IEEE80211_BAND_2GHZ;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03005726 wl->channel_type = NL80211_CHAN_NO_HT;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005727 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005728 wl->sg_enabled = true;
Arik Nemtsov66340e52012-06-10 17:09:22 +03005729 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Luciano Coelhoc108c902012-11-26 18:05:49 +02005730 wl->recovery_count = 0;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005731 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005732 wl->ap_ps_map = 0;
5733 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005734 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005735 wl->platform_quirks = 0;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005736 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005737 wl->active_sta_count = 0;
Arik Nemtsov9a100962012-11-28 11:42:42 +02005738 wl->active_link_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005739 wl->fwlog_size = 0;
5740 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005741
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005742 /* The system link is always allocated */
5743 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5744
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005745 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Arik Nemtsov72b06242011-12-07 21:21:51 +02005746 for (i = 0; i < wl->num_tx_desc; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005747 wl->tx_frames[i] = NULL;
5748
5749 spin_lock_init(&wl->wl_lock);
5750
Ido Yariv4cc53382012-07-24 19:18:49 +03005751 wl->state = WLCORE_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005752 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005753 mutex_init(&wl->mutex);
Arik Nemtsov2c388492012-05-18 07:46:39 +03005754 mutex_init(&wl->flush_mutex);
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005755 init_completion(&wl->nvs_loading_complete);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005756
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005757 order = get_order(aggr_buf_size);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005758 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5759 if (!wl->aggr_buf) {
5760 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005761 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005762 }
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005763 wl->aggr_buf_size = aggr_buf_size;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005764
Ido Yariv990f5de2011-03-31 10:06:59 +02005765 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5766 if (!wl->dummy_packet) {
5767 ret = -ENOMEM;
5768 goto err_aggr;
5769 }
5770
Ido Yariv95dac04f2011-06-06 14:57:06 +03005771 /* Allocate one page for the FW log */
5772 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5773 if (!wl->fwlog) {
5774 ret = -ENOMEM;
5775 goto err_dummy_packet;
5776 }
5777
Eliad Pellerc50a2822012-11-22 18:06:19 +02005778 wl->mbox_size = mbox_size;
5779 wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA);
Mircea Gherzan690142e2012-03-17 18:41:53 +01005780 if (!wl->mbox) {
5781 ret = -ENOMEM;
5782 goto err_fwlog;
5783 }
5784
Ido Yariv2e07d022012-11-28 11:42:49 +02005785 wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL);
5786 if (!wl->buffer_32) {
5787 ret = -ENOMEM;
5788 goto err_mbox;
5789 }
5790
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005791 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005792
Ido Yariv2e07d022012-11-28 11:42:49 +02005793err_mbox:
5794 kfree(wl->mbox);
5795
Mircea Gherzan690142e2012-03-17 18:41:53 +01005796err_fwlog:
5797 free_page((unsigned long)wl->fwlog);
5798
Ido Yariv990f5de2011-03-31 10:06:59 +02005799err_dummy_packet:
5800 dev_kfree_skb(wl->dummy_packet);
5801
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005802err_aggr:
5803 free_pages((unsigned long)wl->aggr_buf, order);
5804
Eliad Peller92ef8962011-06-07 12:50:46 +03005805err_wq:
5806 destroy_workqueue(wl->freezable_wq);
5807
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005808err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005809 wl1271_debugfs_exit(wl);
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005810 kfree(wl->priv);
5811
5812err_priv_alloc:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005813 ieee80211_free_hw(hw);
5814
5815err_hw_alloc:
5816
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005817 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005818}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005819EXPORT_SYMBOL_GPL(wlcore_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005820
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005821int wlcore_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005822{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005823 /* Unblock any fwlog readers */
5824 mutex_lock(&wl->mutex);
5825 wl->fwlog_size = -1;
5826 wake_up_interruptible_all(&wl->fwlog_waitq);
5827 mutex_unlock(&wl->mutex);
5828
Luciano Coelho33cab572013-05-04 02:46:38 +03005829 wlcore_sysfs_free(wl);
Gery Kahn6f07b722011-07-18 14:21:49 +03005830
Ido Yariv2e07d022012-11-28 11:42:49 +02005831 kfree(wl->buffer_32);
Eliad Pellera8e27822012-11-19 17:14:06 +02005832 kfree(wl->mbox);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005833 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005834 dev_kfree_skb(wl->dummy_packet);
Igal Chernobelsky26a309c2012-07-29 18:21:12 +03005835 free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005836
5837 wl1271_debugfs_exit(wl);
5838
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005839 vfree(wl->fw);
5840 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005841 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005842 kfree(wl->nvs);
5843 wl->nvs = NULL;
5844
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03005845 kfree(wl->fw_status_1);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005846 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005847 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005848
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005849 kfree(wl->priv);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005850 ieee80211_free_hw(wl->hw);
5851
5852 return 0;
5853}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005854EXPORT_SYMBOL_GPL(wlcore_free_hw);
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005855
Johannes Berg964dc9e2013-06-03 17:25:34 +02005856#ifdef CONFIG_PM
5857static const struct wiphy_wowlan_support wlcore_wowlan_support = {
5858 .flags = WIPHY_WOWLAN_ANY,
5859 .n_patterns = WL1271_MAX_RX_FILTERS,
5860 .pattern_min_len = 1,
5861 .pattern_max_len = WL1271_RX_FILTER_MAX_PATTERN_SIZE,
5862};
5863#endif
5864
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005865static void wlcore_nvs_cb(const struct firmware *fw, void *context)
Felipe Balbice2a2172011-10-05 14:12:55 +03005866{
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005867 struct wl1271 *wl = context;
5868 struct platform_device *pdev = wl->pdev;
Luciano Coelhoafb43e62013-01-25 11:57:48 +02005869 struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
5870 struct wl12xx_platform_data *pdata = pdev_data->pdata;
Felipe Balbia390e852011-10-06 10:07:44 +03005871 unsigned long irqflags;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005872 int ret;
Felipe Balbia390e852011-10-06 10:07:44 +03005873
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005874 if (fw) {
5875 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
5876 if (!wl->nvs) {
5877 wl1271_error("Could not allocate nvs data");
5878 goto out;
5879 }
5880 wl->nvs_len = fw->size;
5881 } else {
5882 wl1271_debug(DEBUG_BOOT, "Could not get nvs file %s",
5883 WL12XX_NVS_NAME);
5884 wl->nvs = NULL;
5885 wl->nvs_len = 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005886 }
5887
Ido Yariv3992eb22012-09-02 12:29:27 +03005888 ret = wl->ops->setup(wl);
5889 if (ret < 0)
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005890 goto out_free_nvs;
Ido Yariv3992eb22012-09-02 12:29:27 +03005891
Arik Nemtsov72b06242011-12-07 21:21:51 +02005892 BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
5893
Luciano Coelhoe87288f2011-12-05 16:12:54 +02005894 /* adjust some runtime configuration parameters */
5895 wlcore_adjust_conf(wl);
5896
Felipe Balbia390e852011-10-06 10:07:44 +03005897 wl->irq = platform_get_irq(pdev, 0);
Felipe Balbia390e852011-10-06 10:07:44 +03005898 wl->platform_quirks = pdata->platform_quirks;
Luciano Coelhoafb43e62013-01-25 11:57:48 +02005899 wl->if_ops = pdev_data->if_ops;
Felipe Balbia390e852011-10-06 10:07:44 +03005900
Felipe Balbia390e852011-10-06 10:07:44 +03005901 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5902 irqflags = IRQF_TRIGGER_RISING;
5903 else
5904 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5905
Luciano Coelho97236a02013-03-08 09:41:53 +02005906 ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
5907 irqflags, pdev->name, wl);
Felipe Balbia390e852011-10-06 10:07:44 +03005908 if (ret < 0) {
5909 wl1271_error("request_irq() failed: %d", ret);
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005910 goto out_free_nvs;
Felipe Balbia390e852011-10-06 10:07:44 +03005911 }
5912
Johannes Bergdfb89c52012-06-27 09:23:48 +02005913#ifdef CONFIG_PM
Felipe Balbia390e852011-10-06 10:07:44 +03005914 ret = enable_irq_wake(wl->irq);
5915 if (!ret) {
5916 wl->irq_wake_enabled = true;
5917 device_init_wakeup(wl->dev, 1);
Johannes Berg964dc9e2013-06-03 17:25:34 +02005918 if (pdata->pwr_in_suspend)
5919 wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
Felipe Balbia390e852011-10-06 10:07:44 +03005920 }
Johannes Bergdfb89c52012-06-27 09:23:48 +02005921#endif
Felipe Balbia390e852011-10-06 10:07:44 +03005922 disable_irq(wl->irq);
5923
Luciano Coelho4afc37a2012-05-10 12:14:02 +03005924 ret = wl12xx_get_hw_info(wl);
5925 if (ret < 0) {
5926 wl1271_error("couldn't get hw info");
Luciano Coelho8b425e62012-06-25 14:41:20 +03005927 goto out_irq;
Luciano Coelho4afc37a2012-05-10 12:14:02 +03005928 }
5929
5930 ret = wl->ops->identify_chip(wl);
5931 if (ret < 0)
Luciano Coelho8b425e62012-06-25 14:41:20 +03005932 goto out_irq;
Luciano Coelho4afc37a2012-05-10 12:14:02 +03005933
Felipe Balbia390e852011-10-06 10:07:44 +03005934 ret = wl1271_init_ieee80211(wl);
5935 if (ret)
5936 goto out_irq;
5937
5938 ret = wl1271_register_hw(wl);
5939 if (ret)
5940 goto out_irq;
5941
Luciano Coelho33cab572013-05-04 02:46:38 +03005942 ret = wlcore_sysfs_init(wl);
5943 if (ret)
Luciano Coelho8b425e62012-06-25 14:41:20 +03005944 goto out_unreg;
Felipe Balbif79f8902011-10-06 13:05:25 +03005945
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005946 wl->initialized = true;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005947 goto out;
Felipe Balbia390e852011-10-06 10:07:44 +03005948
Luciano Coelho8b425e62012-06-25 14:41:20 +03005949out_unreg:
5950 wl1271_unregister_hw(wl);
5951
Felipe Balbia390e852011-10-06 10:07:44 +03005952out_irq:
5953 free_irq(wl->irq, wl);
5954
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005955out_free_nvs:
5956 kfree(wl->nvs);
5957
Felipe Balbia390e852011-10-06 10:07:44 +03005958out:
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005959 release_firmware(fw);
5960 complete_all(&wl->nvs_loading_complete);
5961}
5962
Bill Pembertonb74324d2012-12-03 09:56:42 -05005963int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005964{
5965 int ret;
5966
5967 if (!wl->ops || !wl->ptable)
5968 return -EINVAL;
5969
5970 wl->dev = &pdev->dev;
5971 wl->pdev = pdev;
5972 platform_set_drvdata(pdev, wl);
5973
5974 ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
5975 WL12XX_NVS_NAME, &pdev->dev, GFP_KERNEL,
5976 wl, wlcore_nvs_cb);
5977 if (ret < 0) {
5978 wl1271_error("request_firmware_nowait failed: %d", ret);
5979 complete_all(&wl->nvs_loading_complete);
5980 }
5981
Felipe Balbia390e852011-10-06 10:07:44 +03005982 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005983}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005984EXPORT_SYMBOL_GPL(wlcore_probe);
Felipe Balbice2a2172011-10-05 14:12:55 +03005985
Bill Pembertonb74324d2012-12-03 09:56:42 -05005986int wlcore_remove(struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03005987{
Felipe Balbia390e852011-10-06 10:07:44 +03005988 struct wl1271 *wl = platform_get_drvdata(pdev);
5989
Ido Yariv6f8d6b22012-09-02 01:32:47 +03005990 wait_for_completion(&wl->nvs_loading_complete);
5991 if (!wl->initialized)
5992 return 0;
5993
Felipe Balbia390e852011-10-06 10:07:44 +03005994 if (wl->irq_wake_enabled) {
5995 device_init_wakeup(wl->dev, 0);
5996 disable_irq_wake(wl->irq);
5997 }
5998 wl1271_unregister_hw(wl);
5999 free_irq(wl->irq, wl);
Luciano Coelhoffeb5012011-11-21 18:55:51 +02006000 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03006001
Felipe Balbice2a2172011-10-05 14:12:55 +03006002 return 0;
6003}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02006004EXPORT_SYMBOL_GPL(wlcore_remove);
Felipe Balbice2a2172011-10-05 14:12:55 +03006005
Guy Eilam491bbd62011-01-12 10:33:29 +01006006u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02006007EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01006008module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02006009MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
6010
Ido Yariv95dac04f2011-06-06 14:57:06 +03006011module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02006012MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03006013 "FW logger options: continuous, ondemand, dbgpins or disable");
6014
Yair Shapira72303412012-11-26 18:05:50 +02006015module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
Eliad Peller2a5bff02011-08-25 18:10:59 +03006016MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
6017
Yair Shapira72303412012-11-26 18:05:50 +02006018module_param(no_recovery, int, S_IRUSR | S_IWUSR);
Arik Nemtsov34785be2011-12-08 13:06:45 +02006019MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
6020
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02006021MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02006022MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02006023MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Tim Gardner0635ad42012-08-29 13:09:33 -06006024MODULE_FIRMWARE(WL12XX_NVS_NAME);