blob: 085cd17fa07436dd77eeff8f5103efcfb985b735 [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
3 * This file is part of wl1271
4 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03006 *
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/firmware.h>
27#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
29#include <linux/crc32.h>
30#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030031#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020034#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030035#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030036#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
Luciano Coelhoc31be252011-11-21 19:25:24 +020038#include "wlcore.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030039#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030040#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000041#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Arik Nemtsov53d67a52011-12-12 11:32:37 +020052#include "hw_ops.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030053
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020054#define WL1271_BOOT_RETRIES 3
55
Luciano Coelhoe87288f2011-12-05 16:12:54 +020056#define WL1271_BOOT_RETRIES 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +030057
Ido Yariv95dac04f2011-06-06 14:57:06 +030058static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +030059static bool bug_on_recovery;
Arik Nemtsov34785be2011-12-08 13:06:45 +020060static bool no_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +030061
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030062static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +020063 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +030064 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +020065static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +020066static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +020067
Eliad Peller9fd6f212012-03-04 10:55:48 +020068static int wl12xx_set_authorized(struct wl1271 *wl,
69 struct wl12xx_vif *wlvif)
Eliad Pelleref4b29e2011-06-06 13:03:12 +030070{
71 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +020072
Eliad Peller9fd6f212012-03-04 10:55:48 +020073 if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
74 return -EINVAL;
75
76 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030077 return 0;
78
Eliad Peller8181aec2011-10-10 10:13:04 +020079 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +030080 return 0;
81
Eliad Peller154da672011-10-05 11:55:53 +020082 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +030083 if (ret < 0)
84 return ret;
85
Eliad Peller0603d892011-10-05 11:55:51 +020086 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +030087
Eliad Pelleref4b29e2011-06-06 13:03:12 +030088 wl1271_info("Association completed.");
89 return 0;
90}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +030091
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010092static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +020093 struct regulatory_request *request)
94{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +010095 struct ieee80211_supported_band *band;
96 struct ieee80211_channel *ch;
97 int i;
98
99 band = wiphy->bands[IEEE80211_BAND_5GHZ];
100 for (i = 0; i < band->n_channels; i++) {
101 ch = &band->channels[i];
102 if (ch->flags & IEEE80211_CHAN_DISABLED)
103 continue;
104
105 if (ch->flags & IEEE80211_CHAN_RADAR)
106 ch->flags |= IEEE80211_CHAN_NO_IBSS |
107 IEEE80211_CHAN_PASSIVE_SCAN;
108
109 }
110
111 return 0;
112}
113
Eliad Peller9eb599e2011-10-10 10:12:59 +0200114static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
115 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300116{
117 int ret = 0;
118
119 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200120 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300121 if (ret < 0)
122 goto out;
123
124 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200125 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300126 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200127 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300128out:
129 return ret;
130}
131
132/*
133 * this function is being called when the rx_streaming interval
134 * has beed changed or rx_streaming should be disabled
135 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200136int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300137{
138 int ret = 0;
139 int period = wl->conf.rx_streaming.interval;
140
141 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200142 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300143 goto out;
144
145 /* reconfigure/disable according to new streaming_period */
146 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200147 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300148 (wl->conf.rx_streaming.always ||
149 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200150 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300151 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200152 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300153 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200154 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300155 }
156out:
157 return ret;
158}
159
160static void wl1271_rx_streaming_enable_work(struct work_struct *work)
161{
162 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200163 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
164 rx_streaming_enable_work);
165 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300166
167 mutex_lock(&wl->mutex);
168
Eliad Peller0744bdb2011-10-10 10:13:05 +0200169 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200170 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300171 (!wl->conf.rx_streaming.always &&
172 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
173 goto out;
174
175 if (!wl->conf.rx_streaming.interval)
176 goto out;
177
178 ret = wl1271_ps_elp_wakeup(wl);
179 if (ret < 0)
180 goto out;
181
Eliad Peller9eb599e2011-10-10 10:12:59 +0200182 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300183 if (ret < 0)
184 goto out_sleep;
185
186 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200187 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300188 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
189
190out_sleep:
191 wl1271_ps_elp_sleep(wl);
192out:
193 mutex_unlock(&wl->mutex);
194}
195
196static void wl1271_rx_streaming_disable_work(struct work_struct *work)
197{
198 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200199 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
200 rx_streaming_disable_work);
201 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300202
203 mutex_lock(&wl->mutex);
204
Eliad Peller0744bdb2011-10-10 10:13:05 +0200205 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300206 goto out;
207
208 ret = wl1271_ps_elp_wakeup(wl);
209 if (ret < 0)
210 goto out;
211
Eliad Peller9eb599e2011-10-10 10:12:59 +0200212 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300213 if (ret)
214 goto out_sleep;
215
216out_sleep:
217 wl1271_ps_elp_sleep(wl);
218out:
219 mutex_unlock(&wl->mutex);
220}
221
222static void wl1271_rx_streaming_timer(unsigned long data)
223{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200224 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
225 struct wl1271 *wl = wlvif->wl;
226 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300227}
228
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200229/* wl->mutex must be taken */
230void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
231{
232 /* if the watchdog is not armed, don't do anything */
233 if (wl->tx_allocated_blocks == 0)
234 return;
235
236 cancel_delayed_work(&wl->tx_watchdog_work);
237 ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work,
238 msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
239}
240
241static void wl12xx_tx_watchdog_work(struct work_struct *work)
242{
243 struct delayed_work *dwork;
244 struct wl1271 *wl;
245
246 dwork = container_of(work, struct delayed_work, work);
247 wl = container_of(dwork, struct wl1271, tx_watchdog_work);
248
249 mutex_lock(&wl->mutex);
250
251 if (unlikely(wl->state == WL1271_STATE_OFF))
252 goto out;
253
254 /* Tx went out in the meantime - everything is ok */
255 if (unlikely(wl->tx_allocated_blocks == 0))
256 goto out;
257
258 /*
259 * if a ROC is in progress, we might not have any Tx for a long
260 * time (e.g. pending Tx on the non-ROC channels)
261 */
262 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
263 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC",
264 wl->conf.tx.tx_watchdog_timeout);
265 wl12xx_rearm_tx_watchdog_locked(wl);
266 goto out;
267 }
268
269 /*
270 * if a scan is in progress, we might not have any Tx for a long
271 * time
272 */
273 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
274 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan",
275 wl->conf.tx.tx_watchdog_timeout);
276 wl12xx_rearm_tx_watchdog_locked(wl);
277 goto out;
278 }
279
280 /*
281 * AP might cache a frame for a long time for a sleeping station,
282 * so rearm the timer if there's an AP interface with stations. If
283 * Tx is genuinely stuck we will most hopefully discover it when all
284 * stations are removed due to inactivity.
285 */
286 if (wl->active_sta_count) {
287 wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has "
288 " %d stations",
289 wl->conf.tx.tx_watchdog_timeout,
290 wl->active_sta_count);
291 wl12xx_rearm_tx_watchdog_locked(wl);
292 goto out;
293 }
294
295 wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery",
296 wl->conf.tx.tx_watchdog_timeout);
297 wl12xx_queue_recovery_work(wl);
298
299out:
300 mutex_unlock(&wl->mutex);
301}
302
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200303static void wlcore_adjust_conf(struct wl1271 *wl)
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300304{
Ido Yariv95dac04f2011-06-06 14:57:06 +0300305 /* Adjust settings according to optional module parameters */
306 if (fwlog_param) {
307 if (!strcmp(fwlog_param, "continuous")) {
308 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
309 } else if (!strcmp(fwlog_param, "ondemand")) {
310 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
311 } else if (!strcmp(fwlog_param, "dbgpins")) {
312 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
313 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
314 } else if (!strcmp(fwlog_param, "disable")) {
315 wl->conf.fwlog.mem_blocks = 0;
316 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
317 } else {
318 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
319 }
320 }
321}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300322
Eliad Peller6e8cd332011-10-10 10:13:13 +0200323static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
324 struct wl12xx_vif *wlvif,
325 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200326{
Arik Nemtsovda032092011-08-25 12:43:15 +0300327 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200328
Arik Nemtsovb622d992011-02-23 00:22:31 +0200329 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300330 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200331
332 /*
333 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300334 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200335 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300336 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200337 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200338
Arik Nemtsovda032092011-08-25 12:43:15 +0300339 /*
340 * Start high-level PS if the STA is asleep with enough blocks in FW.
341 * Make an exception if this is the only connected station. In this
342 * case FW-memory congestion is not a problem.
343 */
344 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200345 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200346}
347
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300348static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200349 struct wl12xx_vif *wlvif,
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300350 struct wl_fw_status_2 *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200351{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200352 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200353 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300354 u8 hlid, cnt;
355
356 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200357
358 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
359 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
360 wl1271_debug(DEBUG_PSM,
361 "link ps prev 0x%x cur 0x%x changed 0x%x",
362 wl->ap_fw_ps_map, cur_fw_ps_map,
363 wl->ap_fw_ps_map ^ cur_fw_ps_map);
364
365 wl->ap_fw_ps_map = cur_fw_ps_map;
366 }
367
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200368 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
369 lnk = &wl->links[hlid];
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200370 cnt = status->counters.tx_lnk_free_pkts[hlid] -
371 lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200372
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200373 lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid];
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200374 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200375
Eliad Peller6e8cd332011-10-10 10:13:13 +0200376 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
377 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200378 }
379}
380
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300381static int wlcore_fw_status(struct wl1271 *wl,
382 struct wl_fw_status_1 *status_1,
383 struct wl_fw_status_2 *status_2)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200385 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200386 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200387 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300388 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300389 int i;
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200390 size_t status_len;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300391 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300393 status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
394 sizeof(*status_2) + wl->fw_status_priv_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300395
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300396 ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
397 status_len, false);
398 if (ret < 0)
399 return ret;
Shahar Levi13b107d2011-03-06 16:32:12 +0200400
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300401 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
402 "drv_rx_counter = %d, tx_results_counter = %d)",
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300403 status_1->intr,
404 status_1->fw_rx_counter,
405 status_1->drv_rx_counter,
406 status_1->tx_results_counter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300408 for (i = 0; i < NUM_TX_QUEUES; i++) {
409 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300410 wl->tx_allocated_pkts[i] -=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300411 (status_2->counters.tx_released_pkts[i] -
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300412 wl->tx_pkts_freed[i]) & 0xff;
413
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300414 wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300415 }
416
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300417 /* prevent wrap-around in total blocks counter */
418 if (likely(wl->tx_blocks_freed <=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300419 le32_to_cpu(status_2->total_released_blks)))
420 freed_blocks = le32_to_cpu(status_2->total_released_blks) -
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300421 wl->tx_blocks_freed;
422 else
423 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300424 le32_to_cpu(status_2->total_released_blks);
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300425
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300426 wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200427
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300428 wl->tx_allocated_blocks -= freed_blocks;
429
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200430 /*
431 * If the FW freed some blocks:
432 * If we still have allocated blocks - re-arm the timer, Tx is
433 * not stuck. Otherwise, cancel the timer (no Tx currently).
434 */
435 if (freed_blocks) {
436 if (wl->tx_allocated_blocks)
437 wl12xx_rearm_tx_watchdog_locked(wl);
438 else
439 cancel_delayed_work(&wl->tx_watchdog_work);
440 }
441
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300442 avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200443
Eliad Peller4d56ad92011-08-14 13:17:05 +0300444 /*
445 * The FW might change the total number of TX memblocks before
446 * we get a notification about blocks being released. Thus, the
447 * available blocks calculation might yield a temporary result
448 * which is lower than the actual available blocks. Keeping in
449 * mind that only blocks that were allocated can be moved from
450 * TX to RX, tx_blocks_available should never decrease here.
451 */
452 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
453 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Ido Yariva5225502010-10-12 14:49:10 +0200455 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200456 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200457 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300458
Eliad Peller4d56ad92011-08-14 13:17:05 +0300459 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200460 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300461 wl12xx_irq_update_links_status(wl, wlvif, status_2);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200462 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300463
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200465 getnstimeofday(&ts);
466 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300467 (s64)le32_to_cpu(status_2->fw_localtime);
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300468
469 return 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470}
471
Ido Yariva6208652011-03-01 15:14:41 +0200472static void wl1271_flush_deferred_work(struct wl1271 *wl)
473{
474 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200475
Ido Yariva6208652011-03-01 15:14:41 +0200476 /* Pass all received frames to the network stack */
477 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
478 ieee80211_rx_ni(wl->hw, skb);
479
480 /* Return sent skbs to the network stack */
481 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300482 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200483}
484
485static void wl1271_netstack_work(struct work_struct *work)
486{
487 struct wl1271 *wl =
488 container_of(work, struct wl1271, netstack_work);
489
490 do {
491 wl1271_flush_deferred_work(wl);
492 } while (skb_queue_len(&wl->deferred_rx_queue));
493}
494
495#define WL1271_IRQ_MAX_LOOPS 256
496
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300497static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300500 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200501 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200502 struct wl1271 *wl = (struct wl1271 *)cookie;
503 bool done = false;
504 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200505 unsigned long flags;
506
507 /* TX might be handled here, avoid redundant work */
508 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
509 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
Ido Yariv341b7cd2011-03-31 10:07:01 +0200511 /*
512 * In case edge triggered interrupt must be used, we cannot iterate
513 * more than once without introducing race conditions with the hardirq.
514 */
515 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
516 loopcount = 1;
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 mutex_lock(&wl->mutex);
519
520 wl1271_debug(DEBUG_IRQ, "IRQ work");
521
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200522 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523 goto out;
524
Ido Yariva6208652011-03-01 15:14:41 +0200525 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526 if (ret < 0)
527 goto out;
528
Ido Yariva6208652011-03-01 15:14:41 +0200529 while (!done && loopcount--) {
530 /*
531 * In order to avoid a race with the hardirq, clear the flag
532 * before acknowledging the chip. Since the mutex is held,
533 * wl1271_ps_elp_wakeup cannot be called concurrently.
534 */
535 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
536 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200537
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300538 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
539 if (ret < 0) {
540 wl12xx_queue_recovery_work(wl);
541 goto out;
542 }
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;
556 wl12xx_queue_recovery_work(wl);
557
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;
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300566 wl12xx_queue_recovery_work(wl);
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
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300575 wl12xx_rx(wl, wl->fw_status_1);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200576
Ido Yariva5225502010-10-12 14:49:10 +0200577 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200578 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200579 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300580 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200581 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200582 /*
583 * In order to avoid starvation of the TX path,
584 * call the work function directly.
585 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200586 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200587 } else {
588 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200589 }
590
Ido Yariv8aad2462011-03-01 15:14:38 +0200591 /* check for tx results */
Arik Nemtsov53d67a52011-12-12 11:32:37 +0200592 wlcore_hw_tx_delayed_compl(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200593
594 /* Make sure the deferred queues don't get too long */
595 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
596 skb_queue_len(&wl->deferred_rx_queue);
597 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
598 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200599 }
600
601 if (intr & WL1271_ACX_INTR_EVENT_A) {
602 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
603 wl1271_event_handle(wl, 0);
604 }
605
606 if (intr & WL1271_ACX_INTR_EVENT_B) {
607 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
608 wl1271_event_handle(wl, 1);
609 }
610
611 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
612 wl1271_debug(DEBUG_IRQ,
613 "WL1271_ACX_INTR_INIT_COMPLETE");
614
615 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
616 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300617 }
618
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619 wl1271_ps_elp_sleep(wl);
620
621out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200622 spin_lock_irqsave(&wl->wl_lock, flags);
623 /* In case TX was not handled here, queue TX work */
624 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
625 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300626 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200627 ieee80211_queue_work(wl->hw, &wl->tx_work);
628 spin_unlock_irqrestore(&wl->wl_lock, flags);
629
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300630 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200631
632 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633}
634
Eliad Peller4549d092012-02-06 13:07:52 +0200635struct vif_counter_data {
636 u8 counter;
637
638 struct ieee80211_vif *cur_vif;
639 bool cur_vif_running;
640};
641
642static void wl12xx_vif_count_iter(void *data, u8 *mac,
643 struct ieee80211_vif *vif)
644{
645 struct vif_counter_data *counter = data;
646
647 counter->counter++;
648 if (counter->cur_vif == vif)
649 counter->cur_vif_running = true;
650}
651
652/* caller must not hold wl->mutex, as it might deadlock */
653static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
654 struct ieee80211_vif *cur_vif,
655 struct vif_counter_data *data)
656{
657 memset(data, 0, sizeof(*data));
658 data->cur_vif = cur_vif;
659
660 ieee80211_iterate_active_interfaces(hw,
661 wl12xx_vif_count_iter, data);
662}
663
Eliad Peller3fcdab72012-02-06 12:47:54 +0200664static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665{
666 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200667 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200668 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 int ret;
670
Eliad Peller3fcdab72012-02-06 12:47:54 +0200671 if (plt) {
672 fw_type = WL12XX_FW_TYPE_PLT;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200673 fw_name = wl->plt_fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200674 } else {
Eliad Peller4549d092012-02-06 13:07:52 +0200675 /*
676 * we can't call wl12xx_get_vif_count() here because
677 * wl->mutex is taken, so use the cached last_vif_count value
678 */
679 if (wl->last_vif_count > 1) {
680 fw_type = WL12XX_FW_TYPE_MULTI;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200681 fw_name = wl->mr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200682 } else {
683 fw_type = WL12XX_FW_TYPE_NORMAL;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200684 fw_name = wl->sr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200685 }
Eliad Peller3fcdab72012-02-06 12:47:54 +0200686 }
687
688 if (wl->fw_type == fw_type)
689 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200690
691 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
692
Felipe Balbia390e852011-10-06 10:07:44 +0300693 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694
695 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100696 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 return ret;
698 }
699
700 if (fw->size % 4) {
701 wl1271_error("firmware size is not multiple of 32 bits: %zu",
702 fw->size);
703 ret = -EILSEQ;
704 goto out;
705 }
706
Arik Nemtsov166d5042010-10-16 21:44:57 +0200707 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +0200708 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300710 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711
712 if (!wl->fw) {
713 wl1271_error("could not allocate memory for the firmware");
714 ret = -ENOMEM;
715 goto out;
716 }
717
718 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300719 ret = 0;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200720 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721out:
722 release_firmware(fw);
723
724 return ret;
725}
726
Arik Nemtsov3e3947f2012-05-29 18:38:05 +0300727static void wl1271_fetch_nvs(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300728{
729 const struct firmware *fw;
730 int ret;
731
Felipe Balbia390e852011-10-06 10:07:44 +0300732 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
734 if (ret < 0) {
Arik Nemtsov3e3947f2012-05-29 18:38:05 +0300735 wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
736 WL12XX_NVS_NAME, ret);
737 return;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738 }
739
Shahar Levibc765bf2011-03-06 16:32:10 +0200740 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
742 if (!wl->nvs) {
743 wl1271_error("could not allocate memory for the nvs file");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 goto out;
745 }
746
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200747 wl->nvs_len = fw->size;
748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749out:
750 release_firmware(fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300751}
752
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300753void wl12xx_queue_recovery_work(struct wl1271 *wl)
754{
Ido Yarivb666bb72012-05-21 01:10:11 +0300755 /* Avoid a recursive recovery */
756 if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
757 wlcore_disable_interrupts_nosync(wl);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300758 ieee80211_queue_work(wl->hw, &wl->recovery_work);
Ido Yarivb666bb72012-05-21 01:10:11 +0300759 }
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300760}
761
Ido Yariv95dac04f2011-06-06 14:57:06 +0300762size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
763{
764 size_t len = 0;
765
766 /* The FW log is a length-value list, find where the log end */
767 while (len < maxlen) {
768 if (memblock[len] == 0)
769 break;
770 if (len + memblock[len] + 1 > maxlen)
771 break;
772 len += memblock[len] + 1;
773 }
774
775 /* Make sure we have enough room */
776 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
777
778 /* Fill the FW log file, consumed by the sysfs fwlog entry */
779 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
780 wl->fwlog_size += len;
781
782 return len;
783}
784
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300785#define WLCORE_FW_LOG_END 0x2000000
786
Ido Yariv95dac04f2011-06-06 14:57:06 +0300787static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
788{
789 u32 addr;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300790 u32 offset;
791 u32 end_of_log;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300792 u8 *block;
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300793 int ret;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300794
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200795 if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
Ido Yariv95dac04f2011-06-06 14:57:06 +0300796 (wl->conf.fwlog.mem_blocks == 0))
797 return;
798
799 wl1271_info("Reading FW panic log");
800
801 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
802 if (!block)
803 return;
804
805 /*
806 * Make sure the chip is awake and the logger isn't active.
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300807 * Do not send a stop fwlog command if the fw is hanged.
Ido Yariv95dac04f2011-06-06 14:57:06 +0300808 */
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300809 if (wl1271_ps_elp_wakeup(wl))
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300810 goto out;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300811 if (!wl->watchdog_recovery)
812 wl12xx_cmd_stop_fwlog(wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +0300813
814 /* Read the first memory block address */
Ido Yariv8b7c0fc2012-06-17 21:59:42 +0300815 ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
816 if (ret < 0)
817 goto out;
818
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300819 addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
820 if (!addr)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300821 goto out;
822
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300823 if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
824 offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
825 end_of_log = WLCORE_FW_LOG_END;
826 } else {
827 offset = sizeof(addr);
828 end_of_log = addr;
829 }
830
Ido Yariv95dac04f2011-06-06 14:57:06 +0300831 /* Traverse the memory blocks linked list */
Ido Yariv95dac04f2011-06-06 14:57:06 +0300832 do {
833 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
834 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
835 false);
836
837 /*
838 * Memory blocks are linked to one another. The first 4 bytes
839 * of each memory block hold the hardware address of the next
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300840 * one. The last memory block points to the first one in
841 * on demand mode and is equal to 0x2000000 in continuous mode.
Ido Yariv95dac04f2011-06-06 14:57:06 +0300842 */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300843 addr = le32_to_cpup((__le32 *)block);
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300844 if (!wl12xx_copy_fwlog(wl, block + offset,
845 WL12XX_HW_BLOCK_SIZE - offset))
Ido Yariv95dac04f2011-06-06 14:57:06 +0300846 break;
Igal Chernobelsky1e412132012-06-18 11:05:39 +0300847 } while (addr && (addr != end_of_log));
Ido Yariv95dac04f2011-06-06 14:57:06 +0300848
849 wake_up_interruptible(&wl->fwlog_waitq);
850
851out:
852 kfree(block);
853}
854
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200855static void wl1271_recovery_work(struct work_struct *work)
856{
857 struct wl1271 *wl =
858 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +0200859 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +0200860 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200861
862 mutex_lock(&wl->mutex);
863
Eliad Peller3fcdab72012-02-06 12:47:54 +0200864 if (wl->state != WL1271_STATE_ON || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +0200865 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200866
Ido Yariv95dac04f2011-06-06 14:57:06 +0300867 wl12xx_read_fwlog_panic(wl);
868
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300869 /* change partitions momentarily so we can read the FW pc */
870 wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Luciano Coelho06bba802012-05-10 12:14:12 +0300871 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
872 "hint_sts: 0x%08x",
Luciano Coelho00782132011-11-29 13:38:37 +0200873 wl->chip.fw_ver_str,
Luciano Coelho06bba802012-05-10 12:14:12 +0300874 wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
875 wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300876 wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200877
Eliad Pellere9ba7152012-03-04 10:55:54 +0200878 BUG_ON(bug_on_recovery &&
879 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
Eliad Peller2a5bff02011-08-25 18:10:59 +0300880
Arik Nemtsov34785be2011-12-08 13:06:45 +0200881 if (no_recovery) {
882 wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
883 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
884 goto out_unlock;
885 }
886
Oz Krakowskib992c682011-06-26 10:36:02 +0300887 /*
888 * Advance security sequence number to overcome potential progress
889 * in the firmware during recovery. This doens't hurt if the network is
890 * not encrypted.
891 */
Eliad Peller48e93e42011-10-10 10:12:58 +0200892 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +0200893 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +0200894 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +0200895 wlvif->tx_security_seq +=
896 WL1271_TX_SQN_POST_RECOVERY_PADDING;
897 }
Oz Krakowskib992c682011-06-26 10:36:02 +0300898
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300899 /* Prevent spurious TX during FW restart */
Arik Nemtsov66396112012-05-18 07:46:38 +0300900 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300901
Luciano Coelho33c2c062011-05-10 14:46:02 +0300902 if (wl->sched_scanning) {
903 ieee80211_sched_scan_stopped(wl->hw);
904 wl->sched_scanning = false;
905 }
906
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200907 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200908 while (!list_empty(&wl->wlvif_list)) {
909 wlvif = list_first_entry(&wl->wlvif_list,
910 struct wl12xx_vif, list);
911 vif = wl12xx_wlvif_to_vif(wlvif);
912 __wl1271_op_remove_interface(wl, vif, false);
913 }
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300914 wl->watchdog_recovery = false;
Eliad Pellerf0277432011-10-10 10:13:14 +0200915 mutex_unlock(&wl->mutex);
916 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300917
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200918 ieee80211_restart_hw(wl->hw);
919
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300920 /*
921 * Its safe to enable TX now - the queues are stopped after a request
922 * to restart the HW.
923 */
Arik Nemtsov66396112012-05-18 07:46:38 +0300924 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
Eliad Pellerf0277432011-10-10 10:13:14 +0200925 return;
926out_unlock:
Yoni Divinskyafbe3712012-05-16 11:34:18 +0300927 wl->watchdog_recovery = false;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200928 mutex_unlock(&wl->mutex);
929}
930
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931static void wl1271_fw_wakeup(struct wl1271 *wl)
932{
Luciano Coelho00782132011-11-29 13:38:37 +0200933 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934}
935
936static int wl1271_setup(struct wl1271 *wl)
937{
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300938 wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
Luciano Coelho4f64a1e2012-05-10 12:14:00 +0300939 sizeof(*wl->fw_status_2) +
940 wl->fw_status_priv_len, GFP_KERNEL);
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300941 if (!wl->fw_status_1)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 return -ENOMEM;
943
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300944 wl->fw_status_2 = (struct wl_fw_status_2 *)
945 (((u8 *) wl->fw_status_1) +
946 WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
949 if (!wl->tx_res_if) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300950 kfree(wl->fw_status_1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 return -ENOMEM;
952 }
953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954 return 0;
955}
956
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200957static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200959 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200961 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200962 ret = wl1271_power_on(wl);
963 if (ret < 0)
964 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200966 wl1271_io_reset(wl);
967 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968
Luciano Coelho00782132011-11-29 13:38:37 +0200969 wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970
971 /* ELP module wake up */
972 wl1271_fw_wakeup(wl);
973
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200974out:
975 return ret;
976}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977
Eliad Peller3fcdab72012-02-06 12:47:54 +0200978static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200979{
980 int ret = 0;
981
982 ret = wl12xx_set_power_on(wl);
983 if (ret < 0)
984 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +0200986 /*
987 * For wl127x based devices we could use the default block
988 * size (512 bytes), but due to a bug in the sdio driver, we
989 * need to set it explicitly after the chip is powered on. To
990 * simplify the code and since the performance impact is
991 * negligible, we use the same block size for all different
992 * chip types.
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300993 *
994 * Check if the bus supports blocksize alignment and, if it
995 * doesn't, make sure we don't have the quirk.
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +0200996 */
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300997 if (!wl1271_set_block_size(wl))
998 wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001000 /* TODO: make sure the lower driver has set things up correctly */
1001
1002 ret = wl1271_setup(wl);
1003 if (ret < 0)
1004 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005
Eliad Peller3fcdab72012-02-06 12:47:54 +02001006 ret = wl12xx_fetch_firmware(wl, plt);
1007 if (ret < 0)
1008 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010out:
1011 return ret;
1012}
1013
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014int wl1271_plt_start(struct wl1271 *wl)
1015{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001016 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001017 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 int ret;
1019
1020 mutex_lock(&wl->mutex);
1021
1022 wl1271_notice("power up");
1023
1024 if (wl->state != WL1271_STATE_OFF) {
1025 wl1271_error("cannot go into PLT state because not "
1026 "in off state: %d", wl->state);
1027 ret = -EBUSY;
1028 goto out;
1029 }
1030
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001031 while (retries) {
1032 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001033 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001034 if (ret < 0)
1035 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036
Luciano Coelhoc331b342012-05-10 12:13:49 +03001037 ret = wl->ops->plt_init(wl);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001038 if (ret < 0)
1039 goto power_off;
1040
Eliad Peller3fcdab72012-02-06 12:47:54 +02001041 wl->plt = true;
1042 wl->state = WL1271_STATE_ON;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001043 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001044 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001045
Gery Kahn6f07b722011-07-18 14:21:49 +03001046 /* update hw/fw version info in wiphy struct */
1047 wiphy->hw_version = wl->chip.id;
1048 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1049 sizeof(wiphy->fw_version));
1050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 goto out;
1052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001053power_off:
1054 wl1271_power_off(wl);
1055 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001057 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1058 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059out:
1060 mutex_unlock(&wl->mutex);
1061
1062 return ret;
1063}
1064
Ido Yarivf3df1332012-01-11 09:42:39 +02001065int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066{
1067 int ret = 0;
1068
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl1271_notice("power down");
1070
Ido Yariv46b0cc92012-01-11 09:42:41 +02001071 /*
1072 * Interrupts must be disabled before setting the state to OFF.
1073 * Otherwise, the interrupt handler might be called and exit without
1074 * reading the interrupt status.
1075 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001076 wlcore_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001077 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001078 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001079 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001080
1081 /*
1082 * This will not necessarily enable interrupts as interrupts
1083 * may have been disabled when op_stop was called. It will,
1084 * however, balance the above call to disable_interrupts().
1085 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001086 wlcore_enable_interrupts(wl);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001087
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088 wl1271_error("cannot power down because not in PLT "
1089 "state: %d", wl->state);
1090 ret = -EBUSY;
1091 goto out;
1092 }
1093
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001095
Ido Yariva6208652011-03-01 15:14:41 +02001096 wl1271_flush_deferred_work(wl);
1097 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001098 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001099 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001100 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03001101 cancel_delayed_work_sync(&wl->connection_loss_work);
Ido Yariva4549692012-01-11 09:42:40 +02001102
1103 mutex_lock(&wl->mutex);
1104 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001105 wl->flags = 0;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001106 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001107 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001108 wl->plt = false;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001109 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001110 mutex_unlock(&wl->mutex);
1111
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001112out:
1113 return ret;
1114}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001115
Johannes Berg7bb45682011-02-24 14:42:06 +01001116static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001117{
1118 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001119 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1120 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001121 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001122 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001123 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001124 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125
Eliad Peller0f168012011-10-11 13:52:25 +02001126 if (vif)
1127 wlvif = wl12xx_vif_to_data(vif);
1128
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001129 mapping = skb_get_queue_mapping(skb);
1130 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001131
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001132 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001133
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001134 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001135
Arik Nemtsov66396112012-05-18 07:46:38 +03001136 /*
1137 * drop the packet if the link is invalid or the queue is stopped
1138 * for any reason but watermark. Watermark is a "soft"-stop so we
1139 * allow these packets through.
1140 */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001141 if (hlid == WL12XX_INVALID_LINK_ID ||
Arik Nemtsov66396112012-05-18 07:46:38 +03001142 (wlvif && !test_bit(hlid, wlvif->links_map)) ||
1143 (wlcore_is_queue_stopped(wl, q) &&
1144 !wlcore_is_queue_stopped_by_reason(wl, q,
1145 WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001146 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001147 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001148 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001149 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150
Eliad Peller8ccd16e2012-03-04 10:55:55 +02001151 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d",
1152 hlid, q, skb->len);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001153 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1154
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001155 wl->tx_queue_count[q]++;
1156
1157 /*
1158 * The workqueue is slow to process the tx_queue and we need stop
1159 * the queue here, otherwise the queue will get too long.
1160 */
1161 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1162 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
Arik Nemtsov66396112012-05-18 07:46:38 +03001163 wlcore_stop_queue_locked(wl, q,
1164 WLCORE_QUEUE_STOP_REASON_WATERMARK);
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001165 }
1166
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167 /*
1168 * The chip specific setup must run before the first TX packet -
1169 * before that, the tx_work will not be initialized!
1170 */
1171
Ido Yarivb07d4032011-03-01 15:14:43 +02001172 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1173 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001174 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001175
Arik Nemtsov04216da2011-08-14 13:17:38 +03001176out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001177 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178}
1179
Shahar Leviae47c452011-03-06 16:32:14 +02001180int wl1271_tx_dummy_packet(struct wl1271 *wl)
1181{
Ido Yariv990f5de2011-03-31 10:06:59 +02001182 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001183 int q;
1184
1185 /* no need to queue a new dummy packet if one is already pending */
1186 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1187 return 0;
1188
1189 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001190
Ido Yariv990f5de2011-03-31 10:06:59 +02001191 spin_lock_irqsave(&wl->wl_lock, flags);
1192 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001193 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001194 spin_unlock_irqrestore(&wl->wl_lock, flags);
1195
1196 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1197 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001198 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001199
1200 /*
1201 * If the FW TX is busy, TX work will be scheduled by the threaded
1202 * interrupt handler function
1203 */
1204 return 0;
1205}
1206
1207/*
1208 * The size of the dummy packet should be at least 1400 bytes. However, in
1209 * order to minimize the number of bus transactions, aligning it to 512 bytes
1210 * boundaries could be beneficial, performance wise
1211 */
1212#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1213
Luciano Coelhocf27d862011-04-01 21:08:23 +03001214static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001215{
1216 struct sk_buff *skb;
1217 struct ieee80211_hdr_3addr *hdr;
1218 unsigned int dummy_packet_size;
1219
1220 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1221 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1222
1223 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001224 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001225 wl1271_warning("Failed to allocate a dummy packet skb");
1226 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001227 }
1228
1229 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1230
1231 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1232 memset(hdr, 0, sizeof(*hdr));
1233 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001234 IEEE80211_STYPE_NULLFUNC |
1235 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001236
Ido Yariv990f5de2011-03-31 10:06:59 +02001237 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001238
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001239 /* Dummy packets require the TID to be management */
1240 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001241
1242 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001243 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001244 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001245
Ido Yariv990f5de2011-03-31 10:06:59 +02001246 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001247}
1248
Ido Yariv990f5de2011-03-31 10:06:59 +02001249
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001250#ifdef CONFIG_PM
Luciano Coelho22479972012-05-16 06:00:00 +03001251static int
1252wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001253{
1254 int num_fields = 0, in_field = 0, fields_size = 0;
1255 int i, pattern_len = 0;
1256
1257 if (!p->mask) {
1258 wl1271_warning("No mask in WoWLAN pattern");
1259 return -EINVAL;
1260 }
1261
1262 /*
1263 * The pattern is broken up into segments of bytes at different offsets
1264 * that need to be checked by the FW filter. Each segment is called
1265 * a field in the FW API. We verify that the total number of fields
1266 * required for this pattern won't exceed FW limits (8)
1267 * as well as the total fields buffer won't exceed the FW limit.
1268 * Note that if there's a pattern which crosses Ethernet/IP header
1269 * boundary a new field is required.
1270 */
1271 for (i = 0; i < p->pattern_len; i++) {
1272 if (test_bit(i, (unsigned long *)p->mask)) {
1273 if (!in_field) {
1274 in_field = 1;
1275 pattern_len = 1;
1276 } else {
1277 if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1278 num_fields++;
1279 fields_size += pattern_len +
1280 RX_FILTER_FIELD_OVERHEAD;
1281 pattern_len = 1;
1282 } else
1283 pattern_len++;
1284 }
1285 } else {
1286 if (in_field) {
1287 in_field = 0;
1288 fields_size += pattern_len +
1289 RX_FILTER_FIELD_OVERHEAD;
1290 num_fields++;
1291 }
1292 }
1293 }
1294
1295 if (in_field) {
1296 fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
1297 num_fields++;
1298 }
1299
1300 if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
1301 wl1271_warning("RX Filter too complex. Too many segments");
1302 return -EINVAL;
1303 }
1304
1305 if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
1306 wl1271_warning("RX filter pattern is too big");
1307 return -E2BIG;
1308 }
1309
1310 return 0;
1311}
1312
Eyal Shapiraa6eab0c2012-03-14 06:32:07 +02001313struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
1314{
1315 return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
1316}
1317
1318void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
1319{
1320 int i;
1321
1322 if (filter == NULL)
1323 return;
1324
1325 for (i = 0; i < filter->num_fields; i++)
1326 kfree(filter->fields[i].pattern);
1327
1328 kfree(filter);
1329}
1330
1331int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
1332 u16 offset, u8 flags,
1333 u8 *pattern, u8 len)
1334{
1335 struct wl12xx_rx_filter_field *field;
1336
1337 if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
1338 wl1271_warning("Max fields per RX filter. can't alloc another");
1339 return -EINVAL;
1340 }
1341
1342 field = &filter->fields[filter->num_fields];
1343
1344 field->pattern = kzalloc(len, GFP_KERNEL);
1345 if (!field->pattern) {
1346 wl1271_warning("Failed to allocate RX filter pattern");
1347 return -ENOMEM;
1348 }
1349
1350 filter->num_fields++;
1351
1352 field->offset = cpu_to_le16(offset);
1353 field->flags = flags;
1354 field->len = len;
1355 memcpy(field->pattern, pattern, len);
1356
1357 return 0;
1358}
1359
1360int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
1361{
1362 int i, fields_size = 0;
1363
1364 for (i = 0; i < filter->num_fields; i++)
1365 fields_size += filter->fields[i].len +
1366 sizeof(struct wl12xx_rx_filter_field) -
1367 sizeof(u8 *);
1368
1369 return fields_size;
1370}
1371
1372void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
1373 u8 *buf)
1374{
1375 int i;
1376 struct wl12xx_rx_filter_field *field;
1377
1378 for (i = 0; i < filter->num_fields; i++) {
1379 field = (struct wl12xx_rx_filter_field *)buf;
1380
1381 field->offset = filter->fields[i].offset;
1382 field->flags = filter->fields[i].flags;
1383 field->len = filter->fields[i].len;
1384
1385 memcpy(&field->pattern, filter->fields[i].pattern, field->len);
1386 buf += sizeof(struct wl12xx_rx_filter_field) -
1387 sizeof(u8 *) + field->len;
1388 }
1389}
1390
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001391/*
1392 * Allocates an RX filter returned through f
1393 * which needs to be freed using rx_filter_free()
1394 */
Luciano Coelho22479972012-05-16 06:00:00 +03001395static int wl1271_convert_wowlan_pattern_to_rx_filter(
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001396 struct cfg80211_wowlan_trig_pkt_pattern *p,
1397 struct wl12xx_rx_filter **f)
1398{
1399 int i, j, ret = 0;
1400 struct wl12xx_rx_filter *filter;
1401 u16 offset;
1402 u8 flags, len;
1403
1404 filter = wl1271_rx_filter_alloc();
1405 if (!filter) {
1406 wl1271_warning("Failed to alloc rx filter");
1407 ret = -ENOMEM;
1408 goto err;
1409 }
1410
1411 i = 0;
1412 while (i < p->pattern_len) {
1413 if (!test_bit(i, (unsigned long *)p->mask)) {
1414 i++;
1415 continue;
1416 }
1417
1418 for (j = i; j < p->pattern_len; j++) {
1419 if (!test_bit(j, (unsigned long *)p->mask))
1420 break;
1421
1422 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
1423 j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
1424 break;
1425 }
1426
1427 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1428 offset = i;
1429 flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
1430 } else {
1431 offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
1432 flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
1433 }
1434
1435 len = j - i;
1436
1437 ret = wl1271_rx_filter_alloc_field(filter,
1438 offset,
1439 flags,
1440 &p->pattern[i], len);
1441 if (ret)
1442 goto err;
1443
1444 i = j;
1445 }
1446
1447 filter->action = FILTER_SIGNAL;
1448
1449 *f = filter;
1450 return 0;
1451
1452err:
1453 wl1271_rx_filter_free(filter);
1454 *f = NULL;
1455
1456 return ret;
1457}
1458
1459static int wl1271_configure_wowlan(struct wl1271 *wl,
1460 struct cfg80211_wowlan *wow)
1461{
1462 int i, ret;
1463
1464 if (!wow || wow->any || !wow->n_patterns) {
1465 wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1466 wl1271_rx_filter_clear_all(wl);
1467 return 0;
1468 }
1469
1470 if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
1471 return -EINVAL;
1472
1473 /* Validate all incoming patterns before clearing current FW state */
1474 for (i = 0; i < wow->n_patterns; i++) {
1475 ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
1476 if (ret) {
1477 wl1271_warning("Bad wowlan pattern %d", i);
1478 return ret;
1479 }
1480 }
1481
1482 wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1483 wl1271_rx_filter_clear_all(wl);
1484
1485 /* Translate WoWLAN patterns into filters */
1486 for (i = 0; i < wow->n_patterns; i++) {
1487 struct cfg80211_wowlan_trig_pkt_pattern *p;
1488 struct wl12xx_rx_filter *filter = NULL;
1489
1490 p = &wow->patterns[i];
1491
1492 ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
1493 if (ret) {
1494 wl1271_warning("Failed to create an RX filter from "
1495 "wowlan pattern %d", i);
1496 goto out;
1497 }
1498
1499 ret = wl1271_rx_filter_enable(wl, i, 1, filter);
1500
1501 wl1271_rx_filter_free(filter);
1502 if (ret)
1503 goto out;
1504 }
1505
1506 ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
1507
1508out:
1509 return ret;
1510}
1511
Eyal Shapiradae728f2012-02-02 12:03:39 +02001512static int wl1271_configure_suspend_sta(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001513 struct wl12xx_vif *wlvif,
1514 struct cfg80211_wowlan *wow)
Eyal Shapiradae728f2012-02-02 12:03:39 +02001515{
1516 int ret = 0;
1517
Eyal Shapiradae728f2012-02-02 12:03:39 +02001518 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001519 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001520
1521 ret = wl1271_ps_elp_wakeup(wl);
1522 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001523 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001524
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001525 wl1271_configure_wowlan(wl, wow);
Eyal Shapiradae728f2012-02-02 12:03:39 +02001526 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1527 wl->conf.conn.suspend_wake_up_event,
1528 wl->conf.conn.suspend_listen_interval);
1529
1530 if (ret < 0)
1531 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1532
Eyal Shapiradae728f2012-02-02 12:03:39 +02001533 wl1271_ps_elp_sleep(wl);
1534
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001535out:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001536 return ret;
1537
1538}
Eliad Peller94390642011-05-13 11:57:13 +03001539
Eliad Peller0603d892011-10-05 11:55:51 +02001540static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1541 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001542{
Eliad Pellere85d1622011-06-27 13:06:43 +03001543 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001544
Eliad Peller53d40d02011-10-10 10:13:02 +02001545 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001546 goto out;
Eliad Pellere85d1622011-06-27 13:06:43 +03001547
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001548 ret = wl1271_ps_elp_wakeup(wl);
1549 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001550 goto out;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001551
Eliad Peller0603d892011-10-05 11:55:51 +02001552 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001553
1554 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001555out:
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001556 return ret;
1557
1558}
1559
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001560static int wl1271_configure_suspend(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001561 struct wl12xx_vif *wlvif,
1562 struct cfg80211_wowlan *wow)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001563{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001564 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001565 return wl1271_configure_suspend_sta(wl, wlvif, wow);
Eliad Peller536129c2011-10-05 11:55:45 +02001566 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001567 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001568 return 0;
1569}
1570
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001571static void wl1271_configure_resume(struct wl1271 *wl,
1572 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001573{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001574 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001575 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001576 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001577
Eyal Shapiradae728f2012-02-02 12:03:39 +02001578 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001579 return;
1580
Eliad Peller94390642011-05-13 11:57:13 +03001581 ret = wl1271_ps_elp_wakeup(wl);
1582 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001583 return;
Eliad Peller94390642011-05-13 11:57:13 +03001584
Eyal Shapiradae728f2012-02-02 12:03:39 +02001585 if (is_sta) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001586 wl1271_configure_wowlan(wl, NULL);
1587
Eyal Shapiradae728f2012-02-02 12:03:39 +02001588 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1589 wl->conf.conn.wake_up_event,
1590 wl->conf.conn.listen_interval);
1591
1592 if (ret < 0)
1593 wl1271_error("resume: wake up conditions failed: %d",
1594 ret);
1595
1596 } else if (is_ap) {
1597 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1598 }
Eliad Peller94390642011-05-13 11:57:13 +03001599
1600 wl1271_ps_elp_sleep(wl);
Eliad Peller94390642011-05-13 11:57:13 +03001601}
1602
Eliad Peller402e48612011-05-13 11:57:09 +03001603static int wl1271_op_suspend(struct ieee80211_hw *hw,
1604 struct cfg80211_wowlan *wow)
1605{
1606 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001607 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001608 int ret;
1609
Eliad Peller402e48612011-05-13 11:57:09 +03001610 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001611 WARN_ON(!wow);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001612
Arik Nemtsovb9239b62012-02-28 00:41:33 +02001613 wl1271_tx_flush(wl);
1614
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001615 mutex_lock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001616 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001617 wl12xx_for_each_wlvif(wl, wlvif) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001618 ret = wl1271_configure_suspend(wl, wlvif, wow);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001619 if (ret < 0) {
Dan Carpentercd840f62012-04-16 13:57:02 +03001620 mutex_unlock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001621 wl1271_warning("couldn't prepare device to suspend");
1622 return ret;
1623 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001624 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001625 mutex_unlock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001626 /* flush any remaining work */
1627 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001628
1629 /*
1630 * disable and re-enable interrupts in order to flush
1631 * the threaded_irq
1632 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001633 wlcore_disable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001634
1635 /*
1636 * set suspended flag to avoid triggering a new threaded_irq
1637 * work. no need for spinlock as interrupts are disabled.
1638 */
1639 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1640
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001641 wlcore_enable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001642 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001643 flush_delayed_work(&wl->elp_work);
1644
Eliad Peller402e48612011-05-13 11:57:09 +03001645 return 0;
1646}
1647
1648static int wl1271_op_resume(struct ieee80211_hw *hw)
1649{
1650 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001651 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001652 unsigned long flags;
1653 bool run_irq_work = false;
1654
Eliad Peller402e48612011-05-13 11:57:09 +03001655 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1656 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001657 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001658
1659 /*
1660 * re-enable irq_work enqueuing, and call irq_work directly if
1661 * there is a pending work.
1662 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001663 spin_lock_irqsave(&wl->wl_lock, flags);
1664 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1665 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1666 run_irq_work = true;
1667 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001668
Eliad Peller4a859df2011-06-06 12:21:52 +03001669 if (run_irq_work) {
1670 wl1271_debug(DEBUG_MAC80211,
1671 "run postponed irq_work directly");
1672 wl1271_irq(0, wl);
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001673 wlcore_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001674 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001675
1676 mutex_lock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001677 wl12xx_for_each_wlvif(wl, wlvif) {
1678 wl1271_configure_resume(wl, wlvif);
1679 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001680 wl->wow_enabled = false;
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001681 mutex_unlock(&wl->mutex);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001682
Eliad Peller402e48612011-05-13 11:57:09 +03001683 return 0;
1684}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001685#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687static int wl1271_op_start(struct ieee80211_hw *hw)
1688{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001689 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1690
1691 /*
1692 * We have to delay the booting of the hardware because
1693 * we need to know the local MAC address before downloading and
1694 * initializing the firmware. The MAC address cannot be changed
1695 * after boot, and without the proper MAC address, the firmware
1696 * will not function properly.
1697 *
1698 * The MAC address is first known when the corresponding interface
1699 * is added. That is where we will initialize the hardware.
1700 */
1701
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001702 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001703}
1704
1705static void wl1271_op_stop(struct ieee80211_hw *hw)
1706{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001707 struct wl1271 *wl = hw->priv;
1708 int i;
1709
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001710 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001711
Ido Yariv46b0cc92012-01-11 09:42:41 +02001712 /*
1713 * Interrupts must be disabled before setting the state to OFF.
1714 * Otherwise, the interrupt handler might be called and exit without
1715 * reading the interrupt status.
1716 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001717 wlcore_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001718 mutex_lock(&wl->mutex);
1719 if (wl->state == WL1271_STATE_OFF) {
Ido Yarivb666bb72012-05-21 01:10:11 +03001720 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
1721 &wl->flags))
1722 wlcore_enable_interrupts(wl);
1723
Eliad Peller10c8cd02011-10-10 10:13:06 +02001724 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001725
1726 /*
1727 * This will not necessarily enable interrupts as interrupts
1728 * may have been disabled when op_stop was called. It will,
1729 * however, balance the above call to disable_interrupts().
1730 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001731 wlcore_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001732 return;
1733 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001734
Eliad Pellerbaf62772011-10-10 10:12:52 +02001735 /*
1736 * this must be before the cancel_work calls below, so that the work
1737 * functions don't perform further work.
1738 */
1739 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001740 mutex_unlock(&wl->mutex);
1741
Eliad Pellerbaf62772011-10-10 10:12:52 +02001742 wl1271_flush_deferred_work(wl);
1743 cancel_delayed_work_sync(&wl->scan_complete_work);
1744 cancel_work_sync(&wl->netstack_work);
1745 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001746 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001747 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03001748 cancel_delayed_work_sync(&wl->connection_loss_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001749
1750 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov66396112012-05-18 07:46:38 +03001751 wl12xx_tx_reset(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001752 mutex_lock(&wl->mutex);
1753
1754 wl1271_power_off(wl);
Ido Yarivb666bb72012-05-21 01:10:11 +03001755 /*
1756 * In case a recovery was scheduled, interrupts were disabled to avoid
1757 * an interrupt storm. Now that the power is down, it is safe to
1758 * re-enable interrupts to balance the disable depth
1759 */
1760 if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1761 wlcore_enable_interrupts(wl);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001762
1763 wl->band = IEEE80211_BAND_2GHZ;
1764
1765 wl->rx_counter = 0;
1766 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001767 wl->channel_type = NL80211_CHAN_NO_HT;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001768 wl->tx_blocks_available = 0;
1769 wl->tx_allocated_blocks = 0;
1770 wl->tx_results_count = 0;
1771 wl->tx_packets_count = 0;
1772 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001773 wl->ap_fw_ps_map = 0;
1774 wl->ap_ps_map = 0;
1775 wl->sched_scanning = false;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03001776 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001777 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1778 memset(wl->links_map, 0, sizeof(wl->links_map));
1779 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1780 wl->active_sta_count = 0;
1781
1782 /* The system link is always allocated */
1783 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1784
1785 /*
1786 * this is performed after the cancel_work calls and the associated
1787 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1788 * get executed before all these vars have been reset.
1789 */
1790 wl->flags = 0;
1791
1792 wl->tx_blocks_freed = 0;
1793
1794 for (i = 0; i < NUM_TX_QUEUES; i++) {
1795 wl->tx_pkts_freed[i] = 0;
1796 wl->tx_allocated_pkts[i] = 0;
1797 }
1798
1799 wl1271_debugfs_reset(wl);
1800
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001801 kfree(wl->fw_status_1);
1802 wl->fw_status_1 = NULL;
1803 wl->fw_status_2 = NULL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001804 kfree(wl->tx_res_if);
1805 wl->tx_res_if = NULL;
1806 kfree(wl->target_mem_map);
1807 wl->target_mem_map = NULL;
1808
1809 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001810}
1811
Eliad Pellere5a359f2011-10-10 10:13:15 +02001812static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1813{
1814 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1815 WL12XX_MAX_RATE_POLICIES);
1816 if (policy >= WL12XX_MAX_RATE_POLICIES)
1817 return -EBUSY;
1818
1819 __set_bit(policy, wl->rate_policies_map);
1820 *idx = policy;
1821 return 0;
1822}
1823
1824static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1825{
1826 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1827 return;
1828
1829 __clear_bit(*idx, wl->rate_policies_map);
1830 *idx = WL12XX_MAX_RATE_POLICIES;
1831}
1832
Eliad Peller536129c2011-10-05 11:55:45 +02001833static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001834{
Eliad Peller536129c2011-10-05 11:55:45 +02001835 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001836 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001837 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001838 return WL1271_ROLE_P2P_GO;
1839 else
1840 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001841
1842 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001843 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001844 return WL1271_ROLE_P2P_CL;
1845 else
1846 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001847
Eliad Peller227e81e2011-08-14 13:17:26 +03001848 case BSS_TYPE_IBSS:
1849 return WL1271_ROLE_IBSS;
1850
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001851 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001852 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001853 }
1854 return WL12XX_INVALID_ROLE_TYPE;
1855}
1856
Eliad Peller83587502011-10-10 10:12:53 +02001857static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001858{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001859 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001860 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001861
Eliad Peller48e93e42011-10-10 10:12:58 +02001862 /* clear everything but the persistent data */
1863 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001864
1865 switch (ieee80211_vif_type_p2p(vif)) {
1866 case NL80211_IFTYPE_P2P_CLIENT:
1867 wlvif->p2p = 1;
1868 /* fall-through */
1869 case NL80211_IFTYPE_STATION:
1870 wlvif->bss_type = BSS_TYPE_STA_BSS;
1871 break;
1872 case NL80211_IFTYPE_ADHOC:
1873 wlvif->bss_type = BSS_TYPE_IBSS;
1874 break;
1875 case NL80211_IFTYPE_P2P_GO:
1876 wlvif->p2p = 1;
1877 /* fall-through */
1878 case NL80211_IFTYPE_AP:
1879 wlvif->bss_type = BSS_TYPE_AP_BSS;
1880 break;
1881 default:
1882 wlvif->bss_type = MAX_BSS_TYPE;
1883 return -EOPNOTSUPP;
1884 }
1885
Eliad Peller0603d892011-10-05 11:55:51 +02001886 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001887 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001888 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001889
Eliad Pellere936bbe2011-10-05 11:55:56 +02001890 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1891 wlvif->bss_type == BSS_TYPE_IBSS) {
1892 /* init sta/ibss data */
1893 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001894 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1895 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1896 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03001897 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
1898 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
1899 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001900 } else {
1901 /* init ap data */
1902 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1903 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001904 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1905 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1906 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1907 wl12xx_allocate_rate_policy(wl,
1908 &wlvif->ap.ucast_rate_idx[i]);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03001909 wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
1910 /*
1911 * TODO: check if basic_rate shouldn't be
1912 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1913 * instead (the same thing for STA above).
1914 */
1915 wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
1916 /* TODO: this seems to be used only for STA, check it */
1917 wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001918 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001919
Eliad Peller83587502011-10-10 10:12:53 +02001920 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1921 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller6a899792011-10-05 11:55:58 +02001922 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1923
Eliad Peller1b92f152011-10-10 10:13:09 +02001924 /*
1925 * mac80211 configures some values globally, while we treat them
1926 * per-interface. thus, on init, we have to copy them from wl
1927 */
1928 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001929 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001930 wlvif->power_level = wl->power_level;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001931 wlvif->channel_type = wl->channel_type;
Eliad Peller1b92f152011-10-10 10:13:09 +02001932
Eliad Peller9eb599e2011-10-10 10:12:59 +02001933 INIT_WORK(&wlvif->rx_streaming_enable_work,
1934 wl1271_rx_streaming_enable_work);
1935 INIT_WORK(&wlvif->rx_streaming_disable_work,
1936 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001937 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001938
Eliad Peller9eb599e2011-10-10 10:12:59 +02001939 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1940 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001941 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001942}
1943
Eliad Peller1d095472011-10-10 10:12:49 +02001944static bool wl12xx_init_fw(struct wl1271 *wl)
1945{
1946 int retries = WL1271_BOOT_RETRIES;
1947 bool booted = false;
1948 struct wiphy *wiphy = wl->hw->wiphy;
1949 int ret;
1950
1951 while (retries) {
1952 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001953 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02001954 if (ret < 0)
1955 goto power_off;
1956
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001957 ret = wl->ops->boot(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02001958 if (ret < 0)
1959 goto power_off;
1960
1961 ret = wl1271_hw_init(wl);
1962 if (ret < 0)
1963 goto irq_disable;
1964
1965 booted = true;
1966 break;
1967
1968irq_disable:
1969 mutex_unlock(&wl->mutex);
1970 /* Unlocking the mutex in the middle of handling is
1971 inherently unsafe. In this case we deem it safe to do,
1972 because we need to let any possibly pending IRQ out of
1973 the system (and while we are WL1271_STATE_OFF the IRQ
1974 work function will not do anything.) Also, any other
1975 possible concurrent operations will fail due to the
1976 current state, hence the wl1271 struct should be safe. */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001977 wlcore_disable_interrupts(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02001978 wl1271_flush_deferred_work(wl);
1979 cancel_work_sync(&wl->netstack_work);
1980 mutex_lock(&wl->mutex);
1981power_off:
1982 wl1271_power_off(wl);
1983 }
1984
1985 if (!booted) {
1986 wl1271_error("firmware boot failed despite %d retries",
1987 WL1271_BOOT_RETRIES);
1988 goto out;
1989 }
1990
1991 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
1992
1993 /* update hw/fw version info in wiphy struct */
1994 wiphy->hw_version = wl->chip.id;
1995 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1996 sizeof(wiphy->fw_version));
1997
1998 /*
1999 * Now we know if 11a is supported (info from the NVS), so disable
2000 * 11a channels if not supported
2001 */
2002 if (!wl->enable_11a)
2003 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2004
2005 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2006 wl->enable_11a ? "" : "not ");
2007
2008 wl->state = WL1271_STATE_ON;
2009out:
2010 return booted;
2011}
2012
Eliad Peller92e712d2011-12-18 20:25:43 +02002013static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2014{
2015 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2016}
2017
Eliad Peller4549d092012-02-06 13:07:52 +02002018/*
2019 * Check whether a fw switch (i.e. moving from one loaded
2020 * fw to another) is needed. This function is also responsible
2021 * for updating wl->last_vif_count, so it must be called before
2022 * loading a non-plt fw (so the correct fw (single-role/multi-role)
2023 * will be used).
2024 */
2025static bool wl12xx_need_fw_change(struct wl1271 *wl,
2026 struct vif_counter_data vif_counter_data,
2027 bool add)
2028{
2029 enum wl12xx_fw_type current_fw = wl->fw_type;
2030 u8 vif_count = vif_counter_data.counter;
2031
2032 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
2033 return false;
2034
2035 /* increase the vif count if this is a new vif */
2036 if (add && !vif_counter_data.cur_vif_running)
2037 vif_count++;
2038
2039 wl->last_vif_count = vif_count;
2040
2041 /* no need for fw change if the device is OFF */
2042 if (wl->state == WL1271_STATE_OFF)
2043 return false;
2044
2045 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2046 return true;
2047 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2048 return true;
2049
2050 return false;
2051}
2052
Eliad Peller3dee4392012-02-06 12:47:56 +02002053/*
2054 * Enter "forced psm". Make sure the sta is in psm against the ap,
2055 * to make the fw switch a bit more disconnection-persistent.
2056 */
2057static void wl12xx_force_active_psm(struct wl1271 *wl)
2058{
2059 struct wl12xx_vif *wlvif;
2060
2061 wl12xx_for_each_wlvif_sta(wl, wlvif) {
2062 wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
2063 }
2064}
2065
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002066static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2067 struct ieee80211_vif *vif)
2068{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002070 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4549d092012-02-06 13:07:52 +02002071 struct vif_counter_data vif_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002073 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002074 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075
Johannes Bergea086352012-01-19 09:29:58 +01002076 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2077 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002078
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002079 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002080 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081
Eliad Peller4549d092012-02-06 13:07:52 +02002082 wl12xx_get_vif_count(hw, vif, &vif_count);
2083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002084 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002085 ret = wl1271_ps_elp_wakeup(wl);
2086 if (ret < 0)
2087 goto out_unlock;
2088
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002089 /*
2090 * in some very corner case HW recovery scenarios its possible to
2091 * get here before __wl1271_op_remove_interface is complete, so
2092 * opt out if that is the case.
2093 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002094 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2095 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002096 ret = -EBUSY;
2097 goto out;
2098 }
2099
Eliad Peller3fcdab72012-02-06 12:47:54 +02002100
Eliad Peller83587502011-10-10 10:12:53 +02002101 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002102 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002103 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002104
Eliad Peller252efa42011-10-05 11:56:00 +02002105 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002106 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002107 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2108 ret = -EINVAL;
2109 goto out;
2110 }
Eliad Peller1d095472011-10-10 10:12:49 +02002111
Eliad Peller4549d092012-02-06 13:07:52 +02002112 if (wl12xx_need_fw_change(wl, vif_count, true)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002113 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002114 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002115 mutex_unlock(&wl->mutex);
2116 wl1271_recovery_work(&wl->recovery_work);
2117 return 0;
2118 }
2119
Eliad Peller784f6942011-10-05 11:55:39 +02002120 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002121 * TODO: after the nvs issue will be solved, move this block
2122 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002123 */
Eliad Peller1d095472011-10-10 10:12:49 +02002124 if (wl->state == WL1271_STATE_OFF) {
2125 /*
2126 * we still need this in order to configure the fw
2127 * while uploading the nvs
2128 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002129 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130
Eliad Peller1d095472011-10-10 10:12:49 +02002131 booted = wl12xx_init_fw(wl);
2132 if (!booted) {
2133 ret = -EINVAL;
2134 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002135 }
Eliad Peller1d095472011-10-10 10:12:49 +02002136 }
Eliad Peller04e80792011-08-14 13:17:09 +03002137
Eliad Peller1d095472011-10-10 10:12:49 +02002138 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2139 wlvif->bss_type == BSS_TYPE_IBSS) {
2140 /*
2141 * The device role is a special role used for
2142 * rx and tx frames prior to association (as
2143 * the STA role can get packets only from
2144 * its associated bssid)
2145 */
Eliad Peller784f6942011-10-05 11:55:39 +02002146 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002147 WL1271_ROLE_DEVICE,
2148 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002149 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002150 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002151 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002152
Eliad Peller1d095472011-10-10 10:12:49 +02002153 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2154 role_type, &wlvif->role_id);
2155 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002156 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002157
2158 ret = wl1271_init_vif_specific(wl, vif);
2159 if (ret < 0)
2160 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002161
Eliad Peller87627212011-10-10 10:12:54 +02002162 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002163 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002164
2165 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2166 wl->ap_count++;
2167 else
2168 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002169out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002170 wl1271_ps_elp_sleep(wl);
2171out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 mutex_unlock(&wl->mutex);
2173
2174 return ret;
2175}
2176
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002177static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002178 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002179 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180{
Eliad Peller536129c2011-10-05 11:55:45 +02002181 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002182 int i, ret;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002183 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002185 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186
Eliad Peller10c8cd02011-10-10 10:13:06 +02002187 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2188 return;
2189
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002190 /* because of hardware recovery, we may get here twice */
2191 if (wl->state != WL1271_STATE_ON)
2192 return;
2193
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002194 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195
Eliad Pellerbaf62772011-10-10 10:12:52 +02002196 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2197 wl->scan_vif == vif) {
Arik Nemtsov55df5af2012-03-03 22:18:00 +02002198 /*
2199 * Rearm the tx watchdog just before idling scan. This
2200 * prevents just-finished scans from triggering the watchdog
2201 */
2202 wl12xx_rearm_tx_watchdog_locked(wl);
2203
Luciano Coelho08688d62010-07-08 17:50:07 +03002204 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002205 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002206 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002207 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002208 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209 }
2210
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002211 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2212 /* disable active roles */
2213 ret = wl1271_ps_elp_wakeup(wl);
2214 if (ret < 0)
2215 goto deinit;
2216
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002217 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2218 wlvif->bss_type == BSS_TYPE_IBSS) {
2219 if (wl12xx_dev_role_started(wlvif))
2220 wl12xx_stop_dev(wl, wlvif);
2221
Eliad Peller7edebf52011-10-05 11:55:52 +02002222 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002223 if (ret < 0)
2224 goto deinit;
2225 }
2226
Eliad Peller0603d892011-10-05 11:55:51 +02002227 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002228 if (ret < 0)
2229 goto deinit;
2230
2231 wl1271_ps_elp_sleep(wl);
2232 }
2233deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002234 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002235 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002236
2237 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2238 wlvif->bss_type == BSS_TYPE_IBSS) {
2239 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2240 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2241 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2242 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2243 } else {
2244 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2245 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2246 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2247 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2248 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2249 wl12xx_free_rate_policy(wl,
2250 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller830be7e2012-03-19 11:32:55 +02002251 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002252 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002253
Eyal Shapira3eba4a02012-03-19 12:06:27 +02002254 dev_kfree_skb(wlvif->probereq);
2255 wlvif->probereq = NULL;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002256 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002257 if (wl->last_wlvif == wlvif)
2258 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002259 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002260 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002261 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002262 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002263
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002264 if (is_ap)
Eliad Pellera4e41302011-10-11 11:49:15 +02002265 wl->ap_count--;
2266 else
2267 wl->sta_count--;
2268
Arik Nemtsov2f18cf72012-06-10 19:10:45 +03002269 /* Last AP, have more stations. Configure according to STA. */
2270 if (wl->ap_count == 0 && is_ap && wl->sta_count) {
2271 u8 sta_auth = wl->conf.conn.sta_sleep_auth;
2272 /* Configure for power according to debugfs */
2273 if (sta_auth != WL1271_PSM_ILLEGAL)
2274 wl1271_acx_sleep_auth(wl, sta_auth);
2275 /* Configure for power always on */
2276 else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
2277 wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
2278 /* Configure for ELP power saving */
2279 else
2280 wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
2281 }
2282
Eliad Pellerbaf62772011-10-10 10:12:52 +02002283 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002284
Eliad Peller9eb599e2011-10-10 10:12:59 +02002285 del_timer_sync(&wlvif->rx_streaming_timer);
2286 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2287 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002288
Eliad Pellerbaf62772011-10-10 10:12:52 +02002289 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002290}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002291
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002292static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2293 struct ieee80211_vif *vif)
2294{
2295 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002296 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002297 struct wl12xx_vif *iter;
Eliad Peller4549d092012-02-06 13:07:52 +02002298 struct vif_counter_data vif_count;
2299 bool cancel_recovery = true;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002300
Eliad Peller4549d092012-02-06 13:07:52 +02002301 wl12xx_get_vif_count(hw, vif, &vif_count);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002302 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002303
2304 if (wl->state == WL1271_STATE_OFF ||
2305 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2306 goto out;
2307
Juuso Oikarinen67353292010-11-18 15:19:02 +02002308 /*
2309 * wl->vif can be null here if someone shuts down the interface
2310 * just when hardware recovery has been started.
2311 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002312 wl12xx_for_each_wlvif(wl, iter) {
2313 if (iter != wlvif)
2314 continue;
2315
Eliad Peller536129c2011-10-05 11:55:45 +02002316 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002317 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002318 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002319 WARN_ON(iter != wlvif);
Eliad Peller4549d092012-02-06 13:07:52 +02002320 if (wl12xx_need_fw_change(wl, vif_count, false)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002321 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002322 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002323 wl12xx_queue_recovery_work(wl);
2324 cancel_recovery = false;
2325 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002326out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002327 mutex_unlock(&wl->mutex);
Eliad Peller4549d092012-02-06 13:07:52 +02002328 if (cancel_recovery)
2329 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330}
2331
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002332static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2333 struct ieee80211_vif *vif,
2334 enum nl80211_iftype new_type, bool p2p)
2335{
Eliad Peller4549d092012-02-06 13:07:52 +02002336 struct wl1271 *wl = hw->priv;
2337 int ret;
2338
2339 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002340 wl1271_op_remove_interface(hw, vif);
2341
Eliad Peller249e9692012-03-04 10:55:50 +02002342 vif->type = new_type;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002343 vif->p2p = p2p;
Eliad Peller4549d092012-02-06 13:07:52 +02002344 ret = wl1271_op_add_interface(hw, vif);
2345
2346 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2347 return ret;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002348}
2349
Eliad Peller87fbcb02011-10-05 11:55:41 +02002350static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2351 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002352{
2353 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002354 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002356 /*
2357 * One of the side effects of the JOIN command is that is clears
2358 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2359 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002360 * Currently the only valid scenario for JOIN during association
2361 * is on roaming, in which case we will also be given new keys.
2362 * Keep the below message for now, unless it starts bothering
2363 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002364 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002365 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002366 wl1271_info("JOIN while associated.");
2367
Eliad Peller5ec8a442012-02-02 12:22:09 +02002368 /* clear encryption type */
2369 wlvif->encryption_type = KEY_NONE;
2370
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002371 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002372 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002373
Eliad Peller227e81e2011-08-14 13:17:26 +03002374 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002375 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002376 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002377 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002378 if (ret < 0)
2379 goto out;
2380
Eliad Pellerba8447f2011-10-10 10:13:00 +02002381 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002382 goto out;
2383
2384 /*
2385 * The join command disable the keep-alive mode, shut down its process,
2386 * and also clear the template config, so we need to reset it all after
2387 * the join. The acx_aid starts the keep-alive process, and the order
2388 * of the commands below is relevant.
2389 */
Eliad Peller0603d892011-10-05 11:55:51 +02002390 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002391 if (ret < 0)
2392 goto out;
2393
Eliad Peller0603d892011-10-05 11:55:51 +02002394 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002395 if (ret < 0)
2396 goto out;
2397
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002398 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002399 if (ret < 0)
2400 goto out;
2401
Eliad Peller0603d892011-10-05 11:55:51 +02002402 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2403 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002404 ACX_KEEP_ALIVE_TPL_VALID);
2405 if (ret < 0)
2406 goto out;
2407
2408out:
2409 return ret;
2410}
2411
Eliad Peller0603d892011-10-05 11:55:51 +02002412static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002413{
2414 int ret;
2415
Eliad Peller52630c52011-10-10 10:13:08 +02002416 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002417 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2418
Shahar Levi6d158ff2011-09-08 13:01:33 +03002419 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002420 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002421 }
2422
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002423 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002424 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002425 if (ret < 0)
2426 goto out;
2427
Oz Krakowskib992c682011-06-26 10:36:02 +03002428 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002429 wlvif->tx_security_last_seq_lsb = 0;
2430 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002431
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002432out:
2433 return ret;
2434}
2435
Eliad Peller87fbcb02011-10-05 11:55:41 +02002436static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002437{
Eliad Peller1b92f152011-10-10 10:13:09 +02002438 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002439 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002440}
2441
Eliad Peller87fbcb02011-10-05 11:55:41 +02002442static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2443 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444{
2445 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002446 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2447
2448 if (idle == cur_idle)
2449 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002450
2451 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002452 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002453 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002454 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 if (ret < 0)
2456 goto out;
2457 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002458 wlvif->rate_set =
2459 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2460 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002461 if (ret < 0)
2462 goto out;
2463 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002464 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002465 ACX_KEEP_ALIVE_TPL_INVALID);
2466 if (ret < 0)
2467 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002468 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002469 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002470 /* The current firmware only supports sched_scan in idle */
2471 if (wl->sched_scanning) {
Yoni Divinsky78f85f52012-05-16 11:34:17 +03002472 wl1271_scan_sched_scan_stop(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002473 ieee80211_sched_scan_stopped(wl->hw);
2474 }
2475
Eliad Peller679a6732011-10-11 11:55:44 +02002476 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002477 if (ret < 0)
2478 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002479 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002480 }
2481
2482out:
2483 return ret;
2484}
2485
Eliad Peller9f259c42011-10-10 10:13:12 +02002486static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2487 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002488{
Eliad Peller9f259c42011-10-10 10:13:12 +02002489 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2490 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491
2492 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2493
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002494 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002495 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002496 ((wlvif->band != conf->channel->band) ||
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002497 (wlvif->channel != channel) ||
2498 (wlvif->channel_type != conf->channel_type))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002499 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002500 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002501 wlvif->band = conf->channel->band;
2502 wlvif->channel = channel;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002503 wlvif->channel_type = conf->channel_type;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002504
Arik Nemtsovebc7e572012-05-10 12:13:34 +03002505 if (is_ap) {
Eliad Peller2812eef2012-06-12 12:45:27 +03002506 wl1271_set_band_rate(wl, wlvif);
Arik Nemtsovebc7e572012-05-10 12:13:34 +03002507 ret = wl1271_init_ap_rates(wl, wlvif);
2508 if (ret < 0)
2509 wl1271_error("AP rate policy change failed %d",
2510 ret);
2511 } else {
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002512 /*
2513 * FIXME: the mac80211 should really provide a fixed
2514 * rate to use here. for now, just use the smallest
2515 * possible rate for the band as a fixed rate for
2516 * association frames and other control messages.
2517 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002518 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002519 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002520
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002521 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002522 wl1271_tx_min_rate_get(wl,
2523 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002524 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002525 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002526 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002527 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002528
Eliad Peller121af042012-03-04 10:55:51 +02002529 /*
2530 * change the ROC channel. do it only if we are
2531 * not idle. otherwise, CROC will be called
2532 * anyway.
2533 */
2534 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2535 &wlvif->flags) &&
2536 wl12xx_dev_role_started(wlvif) &&
2537 !(conf->flags & IEEE80211_CONF_IDLE)) {
2538 ret = wl12xx_stop_dev(wl, wlvif);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002539 if (ret < 0)
Eliad Peller121af042012-03-04 10:55:51 +02002540 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002541
Eliad Peller121af042012-03-04 10:55:51 +02002542 ret = wl12xx_start_dev(wl, wlvif);
2543 if (ret < 0)
2544 return ret;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002545 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002546 }
2547 }
2548
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002549 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002551 if ((conf->flags & IEEE80211_CONF_PS) &&
2552 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002553 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002554
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002555 int ps_mode;
2556 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002557
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002558 if (wl->conf.conn.forced_ps) {
2559 ps_mode = STATION_POWER_SAVE_MODE;
2560 ps_mode_str = "forced";
2561 } else {
2562 ps_mode = STATION_AUTO_PS_MODE;
2563 ps_mode_str = "auto";
2564 }
2565
2566 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2567
2568 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2569
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002570 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002571 wl1271_warning("enter %s ps failed %d",
2572 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002573
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002574 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002575 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002577 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2578
Eliad Peller0603d892011-10-05 11:55:51 +02002579 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002580 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002581 if (ret < 0)
2582 wl1271_warning("exit auto ps failed %d", ret);
2583 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584 }
2585
Eliad Peller6bd65022011-10-10 10:13:11 +02002586 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002587 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002589 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590
Eliad Peller6bd65022011-10-10 10:13:11 +02002591 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592 }
2593
Eliad Peller9f259c42011-10-10 10:13:12 +02002594 return 0;
2595}
2596
2597static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2598{
2599 struct wl1271 *wl = hw->priv;
2600 struct wl12xx_vif *wlvif;
2601 struct ieee80211_conf *conf = &hw->conf;
2602 int channel, ret = 0;
2603
2604 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2605
2606 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2607 " changed 0x%x",
2608 channel,
2609 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2610 conf->power_level,
2611 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2612 changed);
2613
2614 /*
2615 * mac80211 will go to idle nearly immediately after transmitting some
2616 * frames, such as the deauth. To make sure those frames reach the air,
2617 * wait here until the TX queue is fully flushed.
2618 */
Eliad Pellerd1bcb532012-05-15 16:46:56 +03002619 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
2620 ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2621 (conf->flags & IEEE80211_CONF_IDLE)))
Eliad Peller9f259c42011-10-10 10:13:12 +02002622 wl1271_tx_flush(wl);
2623
2624 mutex_lock(&wl->mutex);
2625
2626 /* we support configuring the channel and band even while off */
2627 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2628 wl->band = conf->channel->band;
2629 wl->channel = channel;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002630 wl->channel_type = conf->channel_type;
Eliad Peller9f259c42011-10-10 10:13:12 +02002631 }
2632
2633 if (changed & IEEE80211_CONF_CHANGE_POWER)
2634 wl->power_level = conf->power_level;
2635
2636 if (unlikely(wl->state == WL1271_STATE_OFF))
2637 goto out;
2638
2639 ret = wl1271_ps_elp_wakeup(wl);
2640 if (ret < 0)
2641 goto out;
2642
2643 /* configure each interface */
2644 wl12xx_for_each_wlvif(wl, wlvif) {
2645 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2646 if (ret < 0)
2647 goto out_sleep;
2648 }
2649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002650out_sleep:
2651 wl1271_ps_elp_sleep(wl);
2652
2653out:
2654 mutex_unlock(&wl->mutex);
2655
2656 return ret;
2657}
2658
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002659struct wl1271_filter_params {
2660 bool enabled;
2661 int mc_list_length;
2662 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2663};
2664
Jiri Pirko22bedad32010-04-01 21:22:57 +00002665static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2666 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002669 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002670 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002671
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002672 if (unlikely(wl->state == WL1271_STATE_OFF))
2673 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002674
Juuso Oikarinen74441132009-10-13 12:47:53 +03002675 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002676 if (!fp) {
2677 wl1271_error("Out of memory setting filters.");
2678 return 0;
2679 }
2680
2681 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002682 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002683 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2684 fp->enabled = false;
2685 } else {
2686 fp->enabled = true;
2687 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002688 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002689 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002690 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002691 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002692 }
2693
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002694 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002695}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002697#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2698 FIF_ALLMULTI | \
2699 FIF_FCSFAIL | \
2700 FIF_BCN_PRBRESP_PROMISC | \
2701 FIF_CONTROL | \
2702 FIF_OTHER_BSS)
2703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2705 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002706 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002707{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002708 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002710 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002711
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002712 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713
Arik Nemtsov7d057862010-10-16 19:25:35 +02002714 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2715 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002717 mutex_lock(&wl->mutex);
2718
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002719 *total &= WL1271_SUPPORTED_FILTERS;
2720 changed &= WL1271_SUPPORTED_FILTERS;
2721
2722 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002723 goto out;
2724
Ido Yariva6208652011-03-01 15:14:41 +02002725 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002726 if (ret < 0)
2727 goto out;
2728
Eliad Peller6e8cd332011-10-10 10:13:13 +02002729 wl12xx_for_each_wlvif(wl, wlvif) {
2730 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2731 if (*total & FIF_ALLMULTI)
2732 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2733 false,
2734 NULL, 0);
2735 else if (fp)
2736 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2737 fp->enabled,
2738 fp->mc_list,
2739 fp->mc_list_length);
2740 if (ret < 0)
2741 goto out_sleep;
2742 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002743 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002744
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002745 /*
2746 * the fw doesn't provide an api to configure the filters. instead,
2747 * the filters configuration is based on the active roles / ROC
2748 * state.
2749 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002750
2751out_sleep:
2752 wl1271_ps_elp_sleep(wl);
2753
2754out:
2755 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002756 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002757}
2758
Eliad Peller170d0e62011-10-05 11:56:06 +02002759static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2760 u8 id, u8 key_type, u8 key_size,
2761 const u8 *key, u8 hlid, u32 tx_seq_32,
2762 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763{
2764 struct wl1271_ap_key *ap_key;
2765 int i;
2766
2767 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2768
2769 if (key_size > MAX_KEY_SIZE)
2770 return -EINVAL;
2771
2772 /*
2773 * Find next free entry in ap_keys. Also check we are not replacing
2774 * an existing key.
2775 */
2776 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002777 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778 break;
2779
Eliad Peller170d0e62011-10-05 11:56:06 +02002780 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002781 wl1271_warning("trying to record key replacement");
2782 return -EINVAL;
2783 }
2784 }
2785
2786 if (i == MAX_NUM_KEYS)
2787 return -EBUSY;
2788
2789 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2790 if (!ap_key)
2791 return -ENOMEM;
2792
2793 ap_key->id = id;
2794 ap_key->key_type = key_type;
2795 ap_key->key_size = key_size;
2796 memcpy(ap_key->key, key, key_size);
2797 ap_key->hlid = hlid;
2798 ap_key->tx_seq_32 = tx_seq_32;
2799 ap_key->tx_seq_16 = tx_seq_16;
2800
Eliad Peller170d0e62011-10-05 11:56:06 +02002801 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802 return 0;
2803}
2804
Eliad Peller170d0e62011-10-05 11:56:06 +02002805static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002806{
2807 int i;
2808
2809 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002810 kfree(wlvif->ap.recorded_keys[i]);
2811 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002812 }
2813}
2814
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002815static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002816{
2817 int i, ret = 0;
2818 struct wl1271_ap_key *key;
2819 bool wep_key_added = false;
2820
2821 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002822 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002823 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 break;
2825
Eliad Peller170d0e62011-10-05 11:56:06 +02002826 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002827 hlid = key->hlid;
2828 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002829 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002830
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002831 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002832 key->id, key->key_type,
2833 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002834 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 key->tx_seq_16);
2836 if (ret < 0)
2837 goto out;
2838
2839 if (key->key_type == KEY_WEP)
2840 wep_key_added = true;
2841 }
2842
2843 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002844 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002845 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002846 if (ret < 0)
2847 goto out;
2848 }
2849
2850out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002851 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002852 return ret;
2853}
2854
Eliad Peller536129c2011-10-05 11:55:45 +02002855static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2856 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002857 u8 key_size, const u8 *key, u32 tx_seq_32,
2858 u16 tx_seq_16, struct ieee80211_sta *sta)
2859{
2860 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002861 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002862
2863 if (is_ap) {
2864 struct wl1271_station *wl_sta;
2865 u8 hlid;
2866
2867 if (sta) {
2868 wl_sta = (struct wl1271_station *)sta->drv_priv;
2869 hlid = wl_sta->hlid;
2870 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002871 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002872 }
2873
Eliad Peller53d40d02011-10-10 10:13:02 +02002874 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002875 /*
2876 * We do not support removing keys after AP shutdown.
2877 * Pretend we do to make mac80211 happy.
2878 */
2879 if (action != KEY_ADD_OR_REPLACE)
2880 return 0;
2881
Eliad Peller170d0e62011-10-05 11:56:06 +02002882 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002883 key_type, key_size,
2884 key, hlid, tx_seq_32,
2885 tx_seq_16);
2886 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002887 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002888 id, key_type, key_size,
2889 key, hlid, tx_seq_32,
2890 tx_seq_16);
2891 }
2892
2893 if (ret < 0)
2894 return ret;
2895 } else {
2896 const u8 *addr;
2897 static const u8 bcast_addr[ETH_ALEN] = {
2898 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2899 };
2900
2901 addr = sta ? sta->addr : bcast_addr;
2902
2903 if (is_zero_ether_addr(addr)) {
2904 /* We dont support TX only encryption */
2905 return -EOPNOTSUPP;
2906 }
2907
2908 /* The wl1271 does not allow to remove unicast keys - they
2909 will be cleared automatically on next CMD_JOIN. Ignore the
2910 request silently, as we dont want the mac80211 to emit
2911 an error message. */
2912 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2913 return 0;
2914
Eliad Peller010d3d32011-08-14 13:17:31 +03002915 /* don't remove key if hlid was already deleted */
2916 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002917 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002918 return 0;
2919
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002920 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002921 id, key_type, key_size,
2922 key, addr, tx_seq_32,
2923 tx_seq_16);
2924 if (ret < 0)
2925 return ret;
2926
2927 /* the default WEP key needs to be configured at least once */
2928 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002929 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002930 wlvif->default_key,
2931 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002932 if (ret < 0)
2933 return ret;
2934 }
2935 }
2936
2937 return 0;
2938}
2939
Arik Nemtsova1c597f2012-05-18 07:46:40 +03002940static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 struct ieee80211_vif *vif,
2942 struct ieee80211_sta *sta,
2943 struct ieee80211_key_conf *key_conf)
2944{
2945 struct wl1271 *wl = hw->priv;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03002946
2947 return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
2948}
2949
2950int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
2951 struct ieee80211_vif *vif,
2952 struct ieee80211_sta *sta,
2953 struct ieee80211_key_conf *key_conf)
2954{
Eliad Peller536129c2011-10-05 11:55:45 +02002955 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002957 u32 tx_seq_32 = 0;
2958 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 u8 key_type;
2960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2962
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002963 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002965 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966 key_conf->keylen, key_conf->flags);
2967 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969 mutex_lock(&wl->mutex);
2970
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002971 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2972 ret = -EAGAIN;
2973 goto out_unlock;
2974 }
2975
Ido Yariva6208652011-03-01 15:14:41 +02002976 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977 if (ret < 0)
2978 goto out_unlock;
2979
Johannes Berg97359d12010-08-10 09:46:38 +02002980 switch (key_conf->cipher) {
2981 case WLAN_CIPHER_SUITE_WEP40:
2982 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 key_type = KEY_WEP;
2984
2985 key_conf->hw_key_idx = key_conf->keyidx;
2986 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002987 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 key_type = KEY_TKIP;
2989
2990 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002991 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2992 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002994 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002995 key_type = KEY_AES;
2996
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002997 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002998 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2999 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003001 case WL1271_CIPHER_SUITE_GEM:
3002 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02003003 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3004 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003005 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003007 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003008
3009 ret = -EOPNOTSUPP;
3010 goto out_sleep;
3011 }
3012
3013 switch (cmd) {
3014 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003015 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003016 key_conf->keyidx, key_type,
3017 key_conf->keylen, key_conf->key,
3018 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 if (ret < 0) {
3020 wl1271_error("Could not add or replace key");
3021 goto out_sleep;
3022 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02003023
3024 /*
3025 * reconfiguring arp response if the unicast (or common)
3026 * encryption key type was changed
3027 */
3028 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
3029 (sta || key_type == KEY_WEP) &&
3030 wlvif->encryption_type != key_type) {
3031 wlvif->encryption_type = key_type;
3032 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3033 if (ret < 0) {
3034 wl1271_warning("build arp rsp failed: %d", ret);
3035 goto out_sleep;
3036 }
3037 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 break;
3039
3040 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003041 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003042 key_conf->keyidx, key_type,
3043 key_conf->keylen, key_conf->key,
3044 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045 if (ret < 0) {
3046 wl1271_error("Could not remove key");
3047 goto out_sleep;
3048 }
3049 break;
3050
3051 default:
3052 wl1271_error("Unsupported key cmd 0x%x", cmd);
3053 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003054 break;
3055 }
3056
3057out_sleep:
3058 wl1271_ps_elp_sleep(wl);
3059
3060out_unlock:
3061 mutex_unlock(&wl->mutex);
3062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003063 return ret;
3064}
Arik Nemtsova1c597f2012-05-18 07:46:40 +03003065EXPORT_SYMBOL_GPL(wlcore_set_key);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003066
3067static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003068 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003069 struct cfg80211_scan_request *req)
3070{
3071 struct wl1271 *wl = hw->priv;
3072 int ret;
3073 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003074 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003075
3076 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3077
3078 if (req->n_ssids) {
3079 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003080 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003081 }
3082
3083 mutex_lock(&wl->mutex);
3084
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003085 if (wl->state == WL1271_STATE_OFF) {
3086 /*
3087 * We cannot return -EBUSY here because cfg80211 will expect
3088 * a call to ieee80211_scan_completed if we do - in this case
3089 * there won't be any call.
3090 */
3091 ret = -EAGAIN;
3092 goto out;
3093 }
3094
Ido Yariva6208652011-03-01 15:14:41 +02003095 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003096 if (ret < 0)
3097 goto out;
3098
Eliad Peller97fd3112012-03-04 10:55:52 +02003099 /* fail if there is any role in ROC */
3100 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
Eliad Peller92e712d2011-12-18 20:25:43 +02003101 /* don't allow scanning right now */
3102 ret = -EBUSY;
3103 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003104 }
3105
Eliad Peller784f6942011-10-05 11:55:39 +02003106 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003107out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003108 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003109out:
3110 mutex_unlock(&wl->mutex);
3111
3112 return ret;
3113}
3114
Eliad Peller73ecce32011-06-27 13:06:45 +03003115static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3116 struct ieee80211_vif *vif)
3117{
3118 struct wl1271 *wl = hw->priv;
3119 int ret;
3120
3121 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3122
3123 mutex_lock(&wl->mutex);
3124
3125 if (wl->state == WL1271_STATE_OFF)
3126 goto out;
3127
3128 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3129 goto out;
3130
3131 ret = wl1271_ps_elp_wakeup(wl);
3132 if (ret < 0)
3133 goto out;
3134
3135 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3136 ret = wl1271_scan_stop(wl);
3137 if (ret < 0)
3138 goto out_sleep;
3139 }
Arik Nemtsov55df5af2012-03-03 22:18:00 +02003140
3141 /*
3142 * Rearm the tx watchdog just before idling scan. This
3143 * prevents just-finished scans from triggering the watchdog
3144 */
3145 wl12xx_rearm_tx_watchdog_locked(wl);
3146
Eliad Peller73ecce32011-06-27 13:06:45 +03003147 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3148 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003149 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003150 wl->scan.req = NULL;
3151 ieee80211_scan_completed(wl->hw, true);
3152
3153out_sleep:
3154 wl1271_ps_elp_sleep(wl);
3155out:
3156 mutex_unlock(&wl->mutex);
3157
3158 cancel_delayed_work_sync(&wl->scan_complete_work);
3159}
3160
Luciano Coelho33c2c062011-05-10 14:46:02 +03003161static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3162 struct ieee80211_vif *vif,
3163 struct cfg80211_sched_scan_request *req,
3164 struct ieee80211_sched_scan_ies *ies)
3165{
3166 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003167 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003168 int ret;
3169
3170 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3171
3172 mutex_lock(&wl->mutex);
3173
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003174 if (wl->state == WL1271_STATE_OFF) {
3175 ret = -EAGAIN;
3176 goto out;
3177 }
3178
Luciano Coelho33c2c062011-05-10 14:46:02 +03003179 ret = wl1271_ps_elp_wakeup(wl);
3180 if (ret < 0)
3181 goto out;
3182
Eliad Peller536129c2011-10-05 11:55:45 +02003183 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003184 if (ret < 0)
3185 goto out_sleep;
3186
Eliad Peller536129c2011-10-05 11:55:45 +02003187 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003188 if (ret < 0)
3189 goto out_sleep;
3190
3191 wl->sched_scanning = true;
3192
3193out_sleep:
3194 wl1271_ps_elp_sleep(wl);
3195out:
3196 mutex_unlock(&wl->mutex);
3197 return ret;
3198}
3199
3200static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3201 struct ieee80211_vif *vif)
3202{
3203 struct wl1271 *wl = hw->priv;
Yoni Divinsky78f85f52012-05-16 11:34:17 +03003204 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003205 int ret;
3206
3207 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3208
3209 mutex_lock(&wl->mutex);
3210
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003211 if (wl->state == WL1271_STATE_OFF)
3212 goto out;
3213
Luciano Coelho33c2c062011-05-10 14:46:02 +03003214 ret = wl1271_ps_elp_wakeup(wl);
3215 if (ret < 0)
3216 goto out;
3217
Yoni Divinsky78f85f52012-05-16 11:34:17 +03003218 wl1271_scan_sched_scan_stop(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003219
3220 wl1271_ps_elp_sleep(wl);
3221out:
3222 mutex_unlock(&wl->mutex);
3223}
3224
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003225static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3226{
3227 struct wl1271 *wl = hw->priv;
3228 int ret = 0;
3229
3230 mutex_lock(&wl->mutex);
3231
3232 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3233 ret = -EAGAIN;
3234 goto out;
3235 }
3236
Ido Yariva6208652011-03-01 15:14:41 +02003237 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003238 if (ret < 0)
3239 goto out;
3240
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003241 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003242 if (ret < 0)
3243 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3244
3245 wl1271_ps_elp_sleep(wl);
3246
3247out:
3248 mutex_unlock(&wl->mutex);
3249
3250 return ret;
3251}
3252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003253static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3254{
3255 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003256 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003257 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003258
3259 mutex_lock(&wl->mutex);
3260
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003261 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3262 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003263 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003264 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003265
Ido Yariva6208652011-03-01 15:14:41 +02003266 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267 if (ret < 0)
3268 goto out;
3269
Eliad Peller6e8cd332011-10-10 10:13:13 +02003270 wl12xx_for_each_wlvif(wl, wlvif) {
3271 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3272 if (ret < 0)
3273 wl1271_warning("set rts threshold failed: %d", ret);
3274 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003275 wl1271_ps_elp_sleep(wl);
3276
3277out:
3278 mutex_unlock(&wl->mutex);
3279
3280 return ret;
3281}
3282
Eliad Peller1fe9f162011-10-05 11:55:48 +02003283static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003284 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003285{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003286 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003287 u8 ssid_len;
3288 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3289 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003290
Eliad Peller889cb362011-05-01 09:56:45 +03003291 if (!ptr) {
3292 wl1271_error("No SSID in IEs!");
3293 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003294 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003295
Eliad Peller889cb362011-05-01 09:56:45 +03003296 ssid_len = ptr[1];
3297 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3298 wl1271_error("SSID is too long!");
3299 return -EINVAL;
3300 }
3301
Eliad Peller1fe9f162011-10-05 11:55:48 +02003302 wlvif->ssid_len = ssid_len;
3303 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003304 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003305}
3306
Eliad Pellerd48055d2011-09-15 12:07:04 +03003307static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3308{
3309 int len;
3310 const u8 *next, *end = skb->data + skb->len;
3311 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3312 skb->len - ieoffset);
3313 if (!ie)
3314 return;
3315 len = ie[1] + 2;
3316 next = ie + len;
3317 memmove(ie, next, end - next);
3318 skb_trim(skb, skb->len - len);
3319}
3320
Eliad Peller26b4bf22011-09-15 12:07:05 +03003321static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3322 unsigned int oui, u8 oui_type,
3323 int ieoffset)
3324{
3325 int len;
3326 const u8 *next, *end = skb->data + skb->len;
3327 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3328 skb->data + ieoffset,
3329 skb->len - ieoffset);
3330 if (!ie)
3331 return;
3332 len = ie[1] + 2;
3333 next = ie + len;
3334 memmove(ie, next, end - next);
3335 skb_trim(skb, skb->len - len);
3336}
3337
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003338static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3339 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003340{
Eliad Pellercdaac622012-01-31 11:57:16 +02003341 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003342 struct sk_buff *skb;
3343 int ret;
3344
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003345 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003346 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003347 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003348
Eliad Pellercdaac622012-01-31 11:57:16 +02003349 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003350 CMD_TEMPL_AP_PROBE_RESPONSE,
3351 skb->data,
3352 skb->len, 0,
3353 rates);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003354 dev_kfree_skb(skb);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003355
3356 if (ret < 0)
3357 goto out;
3358
3359 wl1271_debug(DEBUG_AP, "probe response updated");
3360 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3361
3362out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003363 return ret;
3364}
3365
3366static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3367 struct ieee80211_vif *vif,
3368 u8 *probe_rsp_data,
3369 size_t probe_rsp_len,
3370 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003371{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003372 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3373 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003374 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3375 int ssid_ie_offset, ie_offset, templ_len;
3376 const u8 *ptr;
3377
3378 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003379 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003380 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003381 CMD_TEMPL_AP_PROBE_RESPONSE,
3382 probe_rsp_data,
3383 probe_rsp_len, 0,
3384 rates);
3385
3386 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3387 wl1271_error("probe_rsp template too big");
3388 return -EINVAL;
3389 }
3390
3391 /* start searching from IE offset */
3392 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3393
3394 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3395 probe_rsp_len - ie_offset);
3396 if (!ptr) {
3397 wl1271_error("No SSID in beacon!");
3398 return -EINVAL;
3399 }
3400
3401 ssid_ie_offset = ptr - probe_rsp_data;
3402 ptr += (ptr[1] + 2);
3403
3404 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3405
3406 /* insert SSID from bss_conf */
3407 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3408 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3409 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3410 bss_conf->ssid, bss_conf->ssid_len);
3411 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3412
3413 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3414 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3415 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3416
Eliad Pellercdaac622012-01-31 11:57:16 +02003417 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003418 CMD_TEMPL_AP_PROBE_RESPONSE,
3419 probe_rsp_templ,
3420 templ_len, 0,
3421 rates);
3422}
3423
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003425 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426 struct ieee80211_bss_conf *bss_conf,
3427 u32 changed)
3428{
Eliad Peller0603d892011-10-05 11:55:51 +02003429 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 int ret = 0;
3431
3432 if (changed & BSS_CHANGED_ERP_SLOT) {
3433 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003434 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 else
Eliad Peller0603d892011-10-05 11:55:51 +02003436 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 if (ret < 0) {
3438 wl1271_warning("Set slot time failed %d", ret);
3439 goto out;
3440 }
3441 }
3442
3443 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3444 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003445 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003446 else
Eliad Peller0603d892011-10-05 11:55:51 +02003447 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 }
3449
3450 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3451 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003452 ret = wl1271_acx_cts_protect(wl, wlvif,
3453 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454 else
Eliad Peller0603d892011-10-05 11:55:51 +02003455 ret = wl1271_acx_cts_protect(wl, wlvif,
3456 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457 if (ret < 0) {
3458 wl1271_warning("Set ctsprotect failed %d", ret);
3459 goto out;
3460 }
3461 }
3462
3463out:
3464 return ret;
3465}
3466
Luciano Coelho62c2e572012-05-10 12:14:04 +03003467static int wlcore_set_beacon_template(struct wl1271 *wl,
3468 struct ieee80211_vif *vif,
3469 bool is_ap)
3470{
3471 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3472 struct ieee80211_hdr *hdr;
3473 u32 min_rate;
3474 int ret;
3475 int ieoffset = offsetof(struct ieee80211_mgmt,
3476 u.beacon.variable);
3477 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3478 u16 tmpl_id;
3479
3480 if (!beacon) {
3481 ret = -EINVAL;
3482 goto out;
3483 }
3484
3485 wl1271_debug(DEBUG_MASTER, "beacon updated");
3486
3487 ret = wl1271_ssid_set(vif, beacon, ieoffset);
3488 if (ret < 0) {
3489 dev_kfree_skb(beacon);
3490 goto out;
3491 }
3492 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
3493 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3494 CMD_TEMPL_BEACON;
3495 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
3496 beacon->data,
3497 beacon->len, 0,
3498 min_rate);
3499 if (ret < 0) {
3500 dev_kfree_skb(beacon);
3501 goto out;
3502 }
3503
3504 /*
3505 * In case we already have a probe-resp beacon set explicitly
3506 * by usermode, don't use the beacon data.
3507 */
3508 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3509 goto end_bcn;
3510
3511 /* remove TIM ie from probe response */
3512 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3513
3514 /*
3515 * remove p2p ie from probe response.
3516 * the fw reponds to probe requests that don't include
3517 * the p2p ie. probe requests with p2p ie will be passed,
3518 * and will be responded by the supplicant (the spec
3519 * forbids including the p2p ie when responding to probe
3520 * requests that didn't include it).
3521 */
3522 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3523 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3524
3525 hdr = (struct ieee80211_hdr *) beacon->data;
3526 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3527 IEEE80211_STYPE_PROBE_RESP);
3528 if (is_ap)
3529 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
3530 beacon->data,
3531 beacon->len,
3532 min_rate);
3533 else
3534 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
3535 CMD_TEMPL_PROBE_RESPONSE,
3536 beacon->data,
3537 beacon->len, 0,
3538 min_rate);
3539end_bcn:
3540 dev_kfree_skb(beacon);
3541 if (ret < 0)
3542 goto out;
3543
3544out:
3545 return ret;
3546}
3547
Arik Nemtsove78a2872010-10-16 19:07:21 +02003548static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3549 struct ieee80211_vif *vif,
3550 struct ieee80211_bss_conf *bss_conf,
3551 u32 changed)
3552{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003553 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003554 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 int ret = 0;
3556
3557 if ((changed & BSS_CHANGED_BEACON_INT)) {
3558 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3559 bss_conf->beacon_int);
3560
Eliad Peller6a899792011-10-05 11:55:58 +02003561 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003562 }
3563
Arik Nemtsov560f002412011-11-08 18:46:54 +02003564 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3565 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003566
3567 wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003568 }
3569
Arik Nemtsove78a2872010-10-16 19:07:21 +02003570 if ((changed & BSS_CHANGED_BEACON)) {
Luciano Coelho62c2e572012-05-10 12:14:04 +03003571 ret = wlcore_set_beacon_template(wl, vif, is_ap);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003572 if (ret < 0)
3573 goto out;
3574 }
3575
3576out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003577 if (ret != 0)
3578 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 return ret;
3580}
3581
3582/* AP mode changes */
3583static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003584 struct ieee80211_vif *vif,
3585 struct ieee80211_bss_conf *bss_conf,
3586 u32 changed)
3587{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003588 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003589 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003590
Arik Nemtsove78a2872010-10-16 19:07:21 +02003591 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3592 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003593
Eliad Peller87fbcb02011-10-05 11:55:41 +02003594 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003595 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003596 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003597 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003598
Eliad Peller87fbcb02011-10-05 11:55:41 +02003599 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003600 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003601 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003602 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003603 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003604
Eliad Peller784f6942011-10-05 11:55:39 +02003605 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003606 if (ret < 0)
3607 goto out;
Luciano Coelho62c2e572012-05-10 12:14:04 +03003608
3609 ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
3610 if (ret < 0)
3611 goto out;
3612
3613 ret = wlcore_set_beacon_template(wl, vif, true);
3614 if (ret < 0)
3615 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003616 }
3617
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3619 if (ret < 0)
3620 goto out;
3621
3622 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3623 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003624 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003625 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003626 if (ret < 0)
3627 goto out;
3628
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003629 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003630 if (ret < 0)
3631 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003632
Eliad Peller53d40d02011-10-10 10:13:02 +02003633 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003634 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003635 }
3636 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003637 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003638 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003639 if (ret < 0)
3640 goto out;
3641
Eliad Peller53d40d02011-10-10 10:13:02 +02003642 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003643 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3644 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003645 wl1271_debug(DEBUG_AP, "stopped AP");
3646 }
3647 }
3648 }
3649
Eliad Peller0603d892011-10-05 11:55:51 +02003650 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003651 if (ret < 0)
3652 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003653
3654 /* Handle HT information change */
3655 if ((changed & BSS_CHANGED_HT) &&
3656 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003657 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003658 bss_conf->ht_operation_mode);
3659 if (ret < 0) {
3660 wl1271_warning("Set ht information failed %d", ret);
3661 goto out;
3662 }
3663 }
3664
Arik Nemtsove78a2872010-10-16 19:07:21 +02003665out:
3666 return;
3667}
3668
3669/* STA/IBSS mode changes */
3670static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3671 struct ieee80211_vif *vif,
3672 struct ieee80211_bss_conf *bss_conf,
3673 u32 changed)
3674{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003675 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003676 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003677 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003678 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003679 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003680 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003681 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003682 bool sta_exists = false;
3683 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003684
3685 if (is_ibss) {
3686 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3687 changed);
3688 if (ret < 0)
3689 goto out;
3690 }
3691
Eliad Peller227e81e2011-08-14 13:17:26 +03003692 if (changed & BSS_CHANGED_IBSS) {
3693 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003694 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003695 ibss_joined = true;
3696 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003697 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
Eliad Peller349345a2012-03-04 10:55:45 +02003698 &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02003699 wl1271_unjoin(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003700 }
3701 }
3702
3703 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003704 do_join = true;
3705
3706 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003707 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003708 do_join = true;
3709
Eliad Peller227e81e2011-08-14 13:17:26 +03003710 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003711 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3712 bss_conf->enable_beacon ? "enabled" : "disabled");
3713
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003714 do_join = true;
3715 }
3716
Eliad Peller349345a2012-03-04 10:55:45 +02003717 if (changed & BSS_CHANGED_IDLE && !is_ibss) {
Eliad Pellerc31e4942011-10-23 08:21:55 +02003718 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3719 if (ret < 0)
3720 wl1271_warning("idle mode change failed %d", ret);
3721 }
3722
Arik Nemtsove78a2872010-10-16 19:07:21 +02003723 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003724 bool enable = false;
3725 if (bss_conf->cqm_rssi_thold)
3726 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003727 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003728 bss_conf->cqm_rssi_thold,
3729 bss_conf->cqm_rssi_hyst);
3730 if (ret < 0)
3731 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003732 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003733 }
3734
Eliad Peller446f5ca2012-03-12 14:53:04 +02003735 if (changed & BSS_CHANGED_BSSID)
Eliad Pellercdf09492011-10-05 11:55:44 +02003736 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003737 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003738 if (ret < 0)
3739 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003740
Eliad Peller784f6942011-10-05 11:55:39 +02003741 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003742 if (ret < 0)
3743 goto out;
Eliad Pellerfa287b82010-12-26 09:27:50 +01003744 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003745
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003746 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3747 rcu_read_lock();
3748 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3749 if (!sta)
3750 goto sta_not_found;
3751
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003752 /* save the supp_rates of the ap */
3753 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3754 if (sta->ht_cap.ht_supported)
3755 sta_rate_set |=
Arik Nemtsovb3a47ee2012-05-10 12:13:33 +03003756 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
3757 (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003758 sta_ht_cap = sta->ht_cap;
3759 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003760
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003761sta_not_found:
3762 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003763 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003764
Arik Nemtsove78a2872010-10-16 19:07:21 +02003765 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003766 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003767 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003768 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003769 wlvif->aid = bss_conf->aid;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03003770 wlvif->channel_type = bss_conf->channel_type;
Eliad Peller66677762012-03-04 10:55:53 +02003771 wlvif->beacon_int = bss_conf->beacon_int;
Eliad Peller446f5ca2012-03-12 14:53:04 +02003772 do_join = true;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003773 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003774
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003775 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003776 * use basic rates from AP, and determine lowest rate
3777 * to use with control frames.
3778 */
3779 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003780 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003781 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003782 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003783 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003784 wl1271_tx_min_rate_get(wl,
3785 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003786 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003787 wlvif->rate_set =
3788 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003789 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003790 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003791 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003792 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003793 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003794
3795 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003796 * with wl1271, we don't need to update the
3797 * beacon_int and dtim_period, because the firmware
3798 * updates it by itself when the first beacon is
3799 * received after a join.
3800 */
Eliad Peller6840e372011-10-05 11:55:50 +02003801 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003802 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003803 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003804
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003805 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003806 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003807 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003808 dev_kfree_skb(wlvif->probereq);
3809 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003810 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003811 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003812 ieoffset = offsetof(struct ieee80211_mgmt,
3813 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003814 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003815
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003816 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003817 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003818 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003819 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003820 } else {
3821 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003822 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003823 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3824 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003825 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003826 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3827 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003828 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003829
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003830 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003831 dev_kfree_skb(wlvif->probereq);
3832 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003833
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003834 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003835 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003836 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003837 wl1271_tx_min_rate_get(wl,
3838 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003839 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003840 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003841 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003842
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003843 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003844 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003845
3846 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003847 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003848 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003849 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003850
3851 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003852 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003853 /*
3854 * we might have to disable roc, if there was
3855 * no IF_OPER_UP notification.
3856 */
3857 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003858 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003859 if (ret < 0)
3860 goto out;
3861 }
3862 /*
3863 * (we also need to disable roc in case of
3864 * roaming on the same channel. until we will
3865 * have a better flow...)
3866 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003867 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3868 ret = wl12xx_croc(wl,
3869 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003870 if (ret < 0)
3871 goto out;
3872 }
3873
Eliad Peller0603d892011-10-05 11:55:51 +02003874 wl1271_unjoin(wl, wlvif);
Eliad Peller8a6a84a2012-03-04 10:55:46 +02003875 if (!bss_conf->idle)
Eliad Peller679a6732011-10-11 11:55:44 +02003876 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003877 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003878 }
3879 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003880
Eliad Pellerd192d262011-05-24 14:33:08 +03003881 if (changed & BSS_CHANGED_IBSS) {
3882 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3883 bss_conf->ibss_joined);
3884
3885 if (bss_conf->ibss_joined) {
3886 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003887 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003888 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003889 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003890 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003891 wl1271_tx_min_rate_get(wl,
3892 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003893
Shahar Levi06b660e2011-09-05 13:54:36 +03003894 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003895 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3896 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003897 if (ret < 0)
3898 goto out;
3899 }
3900 }
3901
Eliad Peller0603d892011-10-05 11:55:51 +02003902 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003903 if (ret < 0)
3904 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003905
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003906 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003907 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003908 if (ret < 0) {
3909 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003910 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003911 }
Eliad Peller251c1772011-08-14 13:17:17 +03003912
3913 /* ROC until connected (after EAPOL exchange) */
3914 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003915 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003916 if (ret < 0)
3917 goto out;
3918
Eliad Peller9fd6f212012-03-04 10:55:48 +02003919 if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
3920 wl12xx_set_authorized(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003921 }
3922 /*
3923 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003924 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003925 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003926 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003927 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003928 if (ret < 0)
3929 goto out;
3930 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003931 }
3932
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003933 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003934 if (sta_exists) {
3935 if ((changed & BSS_CHANGED_HT) &&
3936 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003937 ret = wl1271_acx_set_ht_capabilities(wl,
3938 &sta_ht_cap,
3939 true,
Eliad Peller154da672011-10-05 11:55:53 +02003940 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003941 if (ret < 0) {
3942 wl1271_warning("Set ht cap true failed %d",
3943 ret);
3944 goto out;
3945 }
3946 }
3947 /* handle new association without HT and disassociation */
3948 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003949 ret = wl1271_acx_set_ht_capabilities(wl,
3950 &sta_ht_cap,
3951 false,
Eliad Peller154da672011-10-05 11:55:53 +02003952 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003953 if (ret < 0) {
3954 wl1271_warning("Set ht cap false failed %d",
3955 ret);
3956 goto out;
3957 }
3958 }
3959 }
3960
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003961 /* Handle HT information change. Done after join. */
3962 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003963 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003964 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003965 bss_conf->ht_operation_mode);
3966 if (ret < 0) {
3967 wl1271_warning("Set ht information failed %d", ret);
3968 goto out;
3969 }
3970 }
3971
Eliad Peller76a74c82012-02-02 12:22:11 +02003972 /* Handle arp filtering. Done after join. */
3973 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3974 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3975 __be32 addr = bss_conf->arp_addr_list[0];
3976 wlvif->sta.qos = bss_conf->qos;
3977 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3978
3979 if (bss_conf->arp_addr_cnt == 1 &&
3980 bss_conf->arp_filter_enabled) {
3981 wlvif->ip_addr = addr;
3982 /*
3983 * The template should have been configured only upon
3984 * association. however, it seems that the correct ip
3985 * isn't being set (when sending), so we have to
3986 * reconfigure the template upon every ip change.
3987 */
3988 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3989 if (ret < 0) {
3990 wl1271_warning("build arp rsp failed: %d", ret);
3991 goto out;
3992 }
3993
3994 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3995 (ACX_ARP_FILTER_ARP_FILTERING |
3996 ACX_ARP_FILTER_AUTO_ARP),
3997 addr);
3998 } else {
3999 wlvif->ip_addr = 0;
4000 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
4001 }
4002
4003 if (ret < 0)
4004 goto out;
4005 }
4006
Arik Nemtsove78a2872010-10-16 19:07:21 +02004007out:
4008 return;
4009}
4010
4011static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
4012 struct ieee80211_vif *vif,
4013 struct ieee80211_bss_conf *bss_conf,
4014 u32 changed)
4015{
4016 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004017 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4018 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004019 int ret;
4020
4021 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
4022 (int)changed);
4023
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03004024 /*
4025 * make sure to cancel pending disconnections if our association
4026 * state changed
4027 */
4028 if (!is_ap && (changed & BSS_CHANGED_ASSOC))
4029 cancel_delayed_work_sync(&wl->connection_loss_work);
4030
Eliad Pellerb515d832012-05-15 17:08:56 +03004031 if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
4032 !bss_conf->enable_beacon)
4033 wl1271_tx_flush(wl);
4034
Arik Nemtsove78a2872010-10-16 19:07:21 +02004035 mutex_lock(&wl->mutex);
4036
4037 if (unlikely(wl->state == WL1271_STATE_OFF))
4038 goto out;
4039
Eliad Peller10c8cd02011-10-10 10:13:06 +02004040 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
4041 goto out;
4042
Ido Yariva6208652011-03-01 15:14:41 +02004043 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004044 if (ret < 0)
4045 goto out;
4046
4047 if (is_ap)
4048 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
4049 else
4050 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
4051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004052 wl1271_ps_elp_sleep(wl);
4053
4054out:
4055 mutex_unlock(&wl->mutex);
4056}
4057
Eliad Peller8a3a3c82011-10-02 10:15:52 +02004058static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
4059 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02004060 const struct ieee80211_tx_queue_params *params)
4061{
4062 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004063 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004064 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004065 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004066
4067 mutex_lock(&wl->mutex);
4068
4069 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4070
Kalle Valo4695dc92010-03-18 12:26:38 +02004071 if (params->uapsd)
4072 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4073 else
4074 ps_scheme = CONF_PS_SCHEME_LEGACY;
4075
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004076 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004077 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004078
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004079 ret = wl1271_ps_elp_wakeup(wl);
4080 if (ret < 0)
4081 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004082
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004083 /*
4084 * the txop is confed in units of 32us by the mac80211,
4085 * we need us
4086 */
Eliad Peller0603d892011-10-05 11:55:51 +02004087 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004088 params->cw_min, params->cw_max,
4089 params->aifs, params->txop << 5);
4090 if (ret < 0)
4091 goto out_sleep;
4092
Eliad Peller0603d892011-10-05 11:55:51 +02004093 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004094 CONF_CHANNEL_TYPE_EDCF,
4095 wl1271_tx_get_queue(queue),
4096 ps_scheme, CONF_ACK_POLICY_LEGACY,
4097 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004098
4099out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004100 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004101
4102out:
4103 mutex_unlock(&wl->mutex);
4104
4105 return ret;
4106}
4107
Eliad Peller37a41b42011-09-21 14:06:11 +03004108static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4109 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004110{
4111
4112 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004113 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004114 u64 mactime = ULLONG_MAX;
4115 int ret;
4116
4117 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4118
4119 mutex_lock(&wl->mutex);
4120
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004121 if (unlikely(wl->state == WL1271_STATE_OFF))
4122 goto out;
4123
Ido Yariva6208652011-03-01 15:14:41 +02004124 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004125 if (ret < 0)
4126 goto out;
4127
Eliad Peller9c531142012-01-31 11:57:18 +02004128 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004129 if (ret < 0)
4130 goto out_sleep;
4131
4132out_sleep:
4133 wl1271_ps_elp_sleep(wl);
4134
4135out:
4136 mutex_unlock(&wl->mutex);
4137 return mactime;
4138}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004139
John W. Linvilleece550d2010-07-28 16:41:06 -04004140static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4141 struct survey_info *survey)
4142{
John W. Linvilleece550d2010-07-28 16:41:06 -04004143 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004144
John W. Linvilleece550d2010-07-28 16:41:06 -04004145 if (idx != 0)
4146 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004147
John W. Linvilleece550d2010-07-28 16:41:06 -04004148 survey->channel = conf->channel;
Yoni Divinskyadd779a02012-06-13 18:56:54 +03004149 survey->filled = 0;
John W. Linvilleece550d2010-07-28 16:41:06 -04004150 return 0;
4151}
4152
Arik Nemtsov409622e2011-02-23 00:22:29 +02004153static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004154 struct wl12xx_vif *wlvif,
4155 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156{
4157 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004158 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004159
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004160
4161 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162 wl1271_warning("could not allocate HLID - too much stations");
4163 return -EBUSY;
4164 }
4165
4166 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004167 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4168 if (ret < 0) {
4169 wl1271_warning("could not allocate HLID - too many links");
4170 return -EBUSY;
4171 }
4172
4173 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004174 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004175 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004176 return 0;
4177}
4178
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004179void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004180{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004181 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004182 return;
4183
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004184 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004185 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004186 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004187 __clear_bit(hlid, &wl->ap_ps_map);
4188 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004189 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004190 wl->active_sta_count--;
Arik Nemtsov55df5af2012-03-03 22:18:00 +02004191
4192 /*
4193 * rearm the tx watchdog when the last STA is freed - give the FW a
4194 * chance to return STA-buffered packets before complaining.
4195 */
4196 if (wl->active_sta_count == 0)
4197 wl12xx_rearm_tx_watchdog_locked(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004198}
4199
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004200static int wl12xx_sta_add(struct wl1271 *wl,
4201 struct wl12xx_vif *wlvif,
4202 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004203{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004204 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004205 int ret = 0;
4206 u8 hlid;
4207
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004208 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4209
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004210 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004211 if (ret < 0)
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004212 return ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004213
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004214 wl_sta = (struct wl1271_station *)sta->drv_priv;
4215 hlid = wl_sta->hlid;
4216
Eliad Peller1b92f152011-10-10 10:13:09 +02004217 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004218 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004219 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004220
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004221 return ret;
4222}
4223
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004224static int wl12xx_sta_remove(struct wl1271 *wl,
4225 struct wl12xx_vif *wlvif,
4226 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004227{
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004228 struct wl1271_station *wl_sta;
4229 int ret = 0, id;
4230
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004231 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4232
4233 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004234 id = wl_sta->hlid;
4235 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004236 return -EINVAL;
4237
4238 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
4239 if (ret < 0)
4240 return ret;
4241
4242 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
4243 return ret;
4244}
4245
4246static int wl12xx_update_sta_state(struct wl1271 *wl,
4247 struct wl12xx_vif *wlvif,
4248 struct ieee80211_sta *sta,
4249 enum ieee80211_sta_state old_state,
4250 enum ieee80211_sta_state new_state)
4251{
4252 struct wl1271_station *wl_sta;
4253 u8 hlid;
4254 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
4255 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
4256 int ret;
4257
4258 wl_sta = (struct wl1271_station *)sta->drv_priv;
4259 hlid = wl_sta->hlid;
4260
4261 /* Add station (AP mode) */
4262 if (is_ap &&
4263 old_state == IEEE80211_STA_NOTEXIST &&
4264 new_state == IEEE80211_STA_NONE)
4265 return wl12xx_sta_add(wl, wlvif, sta);
4266
4267 /* Remove station (AP mode) */
4268 if (is_ap &&
4269 old_state == IEEE80211_STA_NONE &&
4270 new_state == IEEE80211_STA_NOTEXIST) {
4271 /* must not fail */
4272 wl12xx_sta_remove(wl, wlvif, sta);
4273 return 0;
4274 }
4275
4276 /* Authorize station (AP mode) */
4277 if (is_ap &&
4278 new_state == IEEE80211_STA_AUTHORIZED) {
4279 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4280 if (ret < 0)
4281 return ret;
4282
4283 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
4284 hlid);
4285 return ret;
4286 }
4287
Eliad Peller9fd6f212012-03-04 10:55:48 +02004288 /* Authorize station */
4289 if (is_sta &&
4290 new_state == IEEE80211_STA_AUTHORIZED) {
4291 set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
4292 return wl12xx_set_authorized(wl, wlvif);
4293 }
4294
4295 if (is_sta &&
4296 old_state == IEEE80211_STA_AUTHORIZED &&
4297 new_state == IEEE80211_STA_ASSOC) {
4298 clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
4299 return 0;
4300 }
4301
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004302 return 0;
4303}
4304
4305static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
4306 struct ieee80211_vif *vif,
4307 struct ieee80211_sta *sta,
4308 enum ieee80211_sta_state old_state,
4309 enum ieee80211_sta_state new_state)
4310{
4311 struct wl1271 *wl = hw->priv;
4312 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4313 int ret;
4314
4315 wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
4316 sta->aid, old_state, new_state);
4317
4318 mutex_lock(&wl->mutex);
4319
4320 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4321 ret = -EBUSY;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004322 goto out;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004323 }
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004324
Ido Yariva6208652011-03-01 15:14:41 +02004325 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004326 if (ret < 0)
4327 goto out;
4328
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004329 ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004330
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004331 wl1271_ps_elp_sleep(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004332out:
4333 mutex_unlock(&wl->mutex);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004334 if (new_state < old_state)
4335 return 0;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004336 return ret;
4337}
4338
Luciano Coelho4623ec72011-03-21 19:26:41 +02004339static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4340 struct ieee80211_vif *vif,
4341 enum ieee80211_ampdu_mlme_action action,
4342 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4343 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004344{
4345 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004346 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004347 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004348 u8 hlid, *ba_bitmap;
4349
4350 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4351 tid);
4352
4353 /* sanity check - the fields in FW are only 8bits wide */
4354 if (WARN_ON(tid > 0xFF))
4355 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004356
4357 mutex_lock(&wl->mutex);
4358
4359 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4360 ret = -EAGAIN;
4361 goto out;
4362 }
4363
Eliad Peller536129c2011-10-05 11:55:45 +02004364 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004365 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004366 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004367 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004368 struct wl1271_station *wl_sta;
4369
4370 wl_sta = (struct wl1271_station *)sta->drv_priv;
4371 hlid = wl_sta->hlid;
4372 ba_bitmap = &wl->links[hlid].ba_bitmap;
4373 } else {
4374 ret = -EINVAL;
4375 goto out;
4376 }
4377
Ido Yariva6208652011-03-01 15:14:41 +02004378 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004379 if (ret < 0)
4380 goto out;
4381
Shahar Levi70559a02011-05-22 16:10:22 +03004382 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4383 tid, action);
4384
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004385 switch (action) {
4386 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004387 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004388 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004389 break;
4390 }
4391
4392 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4393 ret = -EBUSY;
4394 wl1271_error("exceeded max RX BA sessions");
4395 break;
4396 }
4397
4398 if (*ba_bitmap & BIT(tid)) {
4399 ret = -EINVAL;
4400 wl1271_error("cannot enable RX BA session on active "
4401 "tid: %d", tid);
4402 break;
4403 }
4404
4405 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4406 hlid);
4407 if (!ret) {
4408 *ba_bitmap |= BIT(tid);
4409 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004410 }
4411 break;
4412
4413 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004414 if (!(*ba_bitmap & BIT(tid))) {
Arik Nemtsovc9549102012-06-06 10:48:56 +03004415 /*
4416 * this happens on reconfig - so only output a debug
4417 * message for now, and don't fail the function.
4418 */
4419 wl1271_debug(DEBUG_MAC80211,
4420 "no active RX BA session on tid: %d",
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004421 tid);
Arik Nemtsovc9549102012-06-06 10:48:56 +03004422 ret = 0;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004423 break;
4424 }
4425
4426 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4427 hlid);
4428 if (!ret) {
4429 *ba_bitmap &= ~BIT(tid);
4430 wl->ba_rx_session_count--;
4431 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004432 break;
4433
4434 /*
4435 * The BA initiator session management in FW independently.
4436 * Falling break here on purpose for all TX APDU commands.
4437 */
4438 case IEEE80211_AMPDU_TX_START:
4439 case IEEE80211_AMPDU_TX_STOP:
4440 case IEEE80211_AMPDU_TX_OPERATIONAL:
4441 ret = -EINVAL;
4442 break;
4443
4444 default:
4445 wl1271_error("Incorrect ampdu action id=%x\n", action);
4446 ret = -EINVAL;
4447 }
4448
4449 wl1271_ps_elp_sleep(wl);
4450
4451out:
4452 mutex_unlock(&wl->mutex);
4453
4454 return ret;
4455}
4456
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004457static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4458 struct ieee80211_vif *vif,
4459 const struct cfg80211_bitrate_mask *mask)
4460{
Eliad Peller83587502011-10-10 10:12:53 +02004461 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004462 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004463 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004464
4465 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4466 mask->control[NL80211_BAND_2GHZ].legacy,
4467 mask->control[NL80211_BAND_5GHZ].legacy);
4468
4469 mutex_lock(&wl->mutex);
4470
4471 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004472 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004473 wl1271_tx_enabled_rates_get(wl,
4474 mask->control[i].legacy,
4475 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004476
4477 if (unlikely(wl->state == WL1271_STATE_OFF))
4478 goto out;
4479
4480 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4481 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4482
4483 ret = wl1271_ps_elp_wakeup(wl);
4484 if (ret < 0)
4485 goto out;
4486
4487 wl1271_set_band_rate(wl, wlvif);
4488 wlvif->basic_rate =
4489 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4490 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4491
4492 wl1271_ps_elp_sleep(wl);
4493 }
4494out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004495 mutex_unlock(&wl->mutex);
4496
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004497 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004498}
4499
Shahar Levi6d158ff2011-09-08 13:01:33 +03004500static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4501 struct ieee80211_channel_switch *ch_switch)
4502{
4503 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004504 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004505 int ret;
4506
4507 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4508
Arik Nemtsovb9239b62012-02-28 00:41:33 +02004509 wl1271_tx_flush(wl);
4510
Shahar Levi6d158ff2011-09-08 13:01:33 +03004511 mutex_lock(&wl->mutex);
4512
4513 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004514 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4515 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4516 ieee80211_chswitch_done(vif, false);
4517 }
4518 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004519 }
4520
4521 ret = wl1271_ps_elp_wakeup(wl);
4522 if (ret < 0)
4523 goto out;
4524
Eliad Peller52630c52011-10-10 10:13:08 +02004525 /* TODO: change mac80211 to pass vif as param */
4526 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004527 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004528
Eliad Peller52630c52011-10-10 10:13:08 +02004529 if (!ret)
4530 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4531 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004532
4533 wl1271_ps_elp_sleep(wl);
4534
4535out:
4536 mutex_unlock(&wl->mutex);
4537}
4538
Arik Nemtsov33437892011-04-26 23:35:39 +03004539static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4540{
4541 struct wl1271 *wl = hw->priv;
4542 bool ret = false;
4543
4544 mutex_lock(&wl->mutex);
4545
4546 if (unlikely(wl->state == WL1271_STATE_OFF))
4547 goto out;
4548
4549 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004550 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004551out:
4552 mutex_unlock(&wl->mutex);
4553
4554 return ret;
4555}
4556
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004557/* can't be const, mac80211 writes to this */
4558static struct ieee80211_rate wl1271_rates[] = {
4559 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004560 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004562 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004563 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004565 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4566 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004567 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4568 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004569 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4570 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004571 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4572 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004573 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4574 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004575 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4576 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004577 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004578 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4579 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004580 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004581 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4582 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004583 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004584 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4585 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004586 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004587 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4588 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004589 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004590 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4591 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004592 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004593 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4594 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004595 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004596 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4597 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004598};
4599
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004600/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004601static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004602 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004603 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004604 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4605 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4606 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004607 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004608 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4609 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4610 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004611 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004612 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4613 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4614 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004615 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004616};
4617
4618/* can't be const, mac80211 writes to this */
4619static struct ieee80211_supported_band wl1271_band_2ghz = {
4620 .channels = wl1271_channels,
4621 .n_channels = ARRAY_SIZE(wl1271_channels),
4622 .bitrates = wl1271_rates,
4623 .n_bitrates = ARRAY_SIZE(wl1271_rates),
4624};
4625
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004626/* 5 GHz data rates for WL1273 */
4627static struct ieee80211_rate wl1271_rates_5ghz[] = {
4628 { .bitrate = 60,
4629 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4630 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4631 { .bitrate = 90,
4632 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4633 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4634 { .bitrate = 120,
4635 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4636 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4637 { .bitrate = 180,
4638 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4639 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4640 { .bitrate = 240,
4641 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4642 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4643 { .bitrate = 360,
4644 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4645 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4646 { .bitrate = 480,
4647 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4648 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4649 { .bitrate = 540,
4650 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4651 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4652};
4653
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004654/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004655static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004656 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4657 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4658 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4659 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4660 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4661 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4662 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4663 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4664 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4665 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4666 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4667 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4668 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4669 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4670 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4671 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4672 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4673 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4674 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4675 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4676 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4677 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4678 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4679 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4680 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4681 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4682 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4683 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4684 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4685 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4686 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4687 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4688 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4689 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004690};
4691
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004692static struct ieee80211_supported_band wl1271_band_5ghz = {
4693 .channels = wl1271_channels_5ghz,
4694 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4695 .bitrates = wl1271_rates_5ghz,
4696 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004697};
4698
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004699static const struct ieee80211_ops wl1271_ops = {
4700 .start = wl1271_op_start,
4701 .stop = wl1271_op_stop,
4702 .add_interface = wl1271_op_add_interface,
4703 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004704 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004705#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004706 .suspend = wl1271_op_suspend,
4707 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004708#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004709 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004710 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004711 .configure_filter = wl1271_op_configure_filter,
4712 .tx = wl1271_op_tx,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03004713 .set_key = wlcore_op_set_key,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004714 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004715 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004716 .sched_scan_start = wl1271_op_sched_scan_start,
4717 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004718 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004719 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004720 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004721 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004722 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004723 .get_survey = wl1271_op_get_survey,
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004724 .sta_state = wl12xx_op_sta_state,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004725 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004726 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004727 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004728 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004729 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004730};
4731
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004732
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004733u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004734{
4735 u8 idx;
4736
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004737 BUG_ON(band >= 2);
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004738
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004739 if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004740 wl1271_error("Illegal RX rate from HW: %d", rate);
4741 return 0;
4742 }
4743
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004744 idx = wl->band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004745 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4746 wl1271_error("Unsupported RX rate from HW: %d", rate);
4747 return 0;
4748 }
4749
4750 return idx;
4751}
4752
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004753static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4754 struct device_attribute *attr,
4755 char *buf)
4756{
4757 struct wl1271 *wl = dev_get_drvdata(dev);
4758 ssize_t len;
4759
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004760 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004761
4762 mutex_lock(&wl->mutex);
4763 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4764 wl->sg_enabled);
4765 mutex_unlock(&wl->mutex);
4766
4767 return len;
4768
4769}
4770
4771static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4772 struct device_attribute *attr,
4773 const char *buf, size_t count)
4774{
4775 struct wl1271 *wl = dev_get_drvdata(dev);
4776 unsigned long res;
4777 int ret;
4778
Luciano Coelho6277ed62011-04-01 17:49:54 +03004779 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004780 if (ret < 0) {
4781 wl1271_warning("incorrect value written to bt_coex_mode");
4782 return count;
4783 }
4784
4785 mutex_lock(&wl->mutex);
4786
4787 res = !!res;
4788
4789 if (res == wl->sg_enabled)
4790 goto out;
4791
4792 wl->sg_enabled = res;
4793
4794 if (wl->state == WL1271_STATE_OFF)
4795 goto out;
4796
Ido Yariva6208652011-03-01 15:14:41 +02004797 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004798 if (ret < 0)
4799 goto out;
4800
4801 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4802 wl1271_ps_elp_sleep(wl);
4803
4804 out:
4805 mutex_unlock(&wl->mutex);
4806 return count;
4807}
4808
4809static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4810 wl1271_sysfs_show_bt_coex_state,
4811 wl1271_sysfs_store_bt_coex_state);
4812
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004813static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4814 struct device_attribute *attr,
4815 char *buf)
4816{
4817 struct wl1271 *wl = dev_get_drvdata(dev);
4818 ssize_t len;
4819
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004820 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004821
4822 mutex_lock(&wl->mutex);
4823 if (wl->hw_pg_ver >= 0)
4824 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4825 else
4826 len = snprintf(buf, len, "n/a\n");
4827 mutex_unlock(&wl->mutex);
4828
4829 return len;
4830}
4831
Gery Kahn6f07b722011-07-18 14:21:49 +03004832static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004833 wl1271_sysfs_show_hw_pg_ver, NULL);
4834
Ido Yariv95dac04f2011-06-06 14:57:06 +03004835static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4836 struct bin_attribute *bin_attr,
4837 char *buffer, loff_t pos, size_t count)
4838{
4839 struct device *dev = container_of(kobj, struct device, kobj);
4840 struct wl1271 *wl = dev_get_drvdata(dev);
4841 ssize_t len;
4842 int ret;
4843
4844 ret = mutex_lock_interruptible(&wl->mutex);
4845 if (ret < 0)
4846 return -ERESTARTSYS;
4847
4848 /* Let only one thread read the log at a time, blocking others */
4849 while (wl->fwlog_size == 0) {
4850 DEFINE_WAIT(wait);
4851
4852 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4853 &wait,
4854 TASK_INTERRUPTIBLE);
4855
4856 if (wl->fwlog_size != 0) {
4857 finish_wait(&wl->fwlog_waitq, &wait);
4858 break;
4859 }
4860
4861 mutex_unlock(&wl->mutex);
4862
4863 schedule();
4864 finish_wait(&wl->fwlog_waitq, &wait);
4865
4866 if (signal_pending(current))
4867 return -ERESTARTSYS;
4868
4869 ret = mutex_lock_interruptible(&wl->mutex);
4870 if (ret < 0)
4871 return -ERESTARTSYS;
4872 }
4873
4874 /* Check if the fwlog is still valid */
4875 if (wl->fwlog_size < 0) {
4876 mutex_unlock(&wl->mutex);
4877 return 0;
4878 }
4879
4880 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4881 len = min(count, (size_t)wl->fwlog_size);
4882 wl->fwlog_size -= len;
4883 memcpy(buffer, wl->fwlog, len);
4884
4885 /* Make room for new messages */
4886 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4887
4888 mutex_unlock(&wl->mutex);
4889
4890 return len;
4891}
4892
4893static struct bin_attribute fwlog_attr = {
4894 .attr = {.name = "fwlog", .mode = S_IRUSR},
4895 .read = wl1271_sysfs_read_fwlog,
4896};
4897
Luciano Coelho22479972012-05-16 06:00:00 +03004898static void wl1271_connection_loss_work(struct work_struct *work)
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03004899{
4900 struct delayed_work *dwork;
4901 struct wl1271 *wl;
4902 struct ieee80211_vif *vif;
4903 struct wl12xx_vif *wlvif;
4904
4905 dwork = container_of(work, struct delayed_work, work);
4906 wl = container_of(dwork, struct wl1271, connection_loss_work);
4907
4908 wl1271_info("Connection loss work.");
4909
4910 mutex_lock(&wl->mutex);
4911
4912 if (unlikely(wl->state == WL1271_STATE_OFF))
4913 goto out;
4914
4915 /* Call mac80211 connection loss */
4916 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4917 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
4918 goto out;
4919 vif = wl12xx_wlvif_to_vif(wlvif);
4920 ieee80211_connection_loss(vif);
4921 }
4922out:
4923 mutex_unlock(&wl->mutex);
4924}
4925
Luciano Coelho5e037e72011-12-23 09:32:17 +02004926static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4927 u32 oui, u32 nic, int n)
4928{
4929 int i;
4930
4931 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4932 oui, nic, n);
4933
4934 if (nic + n - 1 > 0xffffff)
4935 wl1271_warning("NIC part of the MAC address wraps around!");
4936
4937 for (i = 0; i < n; i++) {
4938 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4939 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4940 wl->addresses[i].addr[2] = (u8) oui;
4941 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4942 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4943 wl->addresses[i].addr[5] = (u8) nic;
4944 nic++;
4945 }
4946
4947 wl->hw->wiphy->n_addresses = n;
4948 wl->hw->wiphy->addresses = wl->addresses;
4949}
4950
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004951static int wl12xx_get_hw_info(struct wl1271 *wl)
4952{
4953 int ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004954
4955 ret = wl12xx_set_power_on(wl);
4956 if (ret < 0)
4957 goto out;
4958
Luciano Coelho00782132011-11-29 13:38:37 +02004959 wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004960
Luciano Coelho00782132011-11-29 13:38:37 +02004961 wl->fuse_oui_addr = 0;
4962 wl->fuse_nic_addr = 0;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004963
Luciano Coelho4ded91c2012-04-11 10:54:52 +03004964 wl->hw_pg_ver = wl->ops->get_pg_ver(wl);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004965
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03004966 if (wl->ops->get_mac)
4967 wl->ops->get_mac(wl);
Luciano Coelho5e037e72011-12-23 09:32:17 +02004968
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004969 wl1271_power_off(wl);
4970out:
4971 return ret;
4972}
4973
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004974static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975{
4976 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004977 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978
4979 if (wl->mac80211_registered)
4980 return 0;
4981
Arik Nemtsov3e3947f2012-05-29 18:38:05 +03004982 wl1271_fetch_nvs(wl);
4983 if (wl->nvs != NULL) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004984 /* NOTE: The wl->nvs->nvs element must be first, in
4985 * order to simplify the casting, we assume it is at
4986 * the beginning of the wl->nvs structure.
4987 */
4988 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004989
Luciano Coelho5e037e72011-12-23 09:32:17 +02004990 oui_addr =
4991 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4992 nic_addr =
4993 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004994 }
4995
Luciano Coelho5e037e72011-12-23 09:32:17 +02004996 /* if the MAC address is zeroed in the NVS derive from fuse */
4997 if (oui_addr == 0 && nic_addr == 0) {
4998 oui_addr = wl->fuse_oui_addr;
4999 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
5000 nic_addr = wl->fuse_nic_addr + 1;
5001 }
5002
5003 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004
5005 ret = ieee80211_register_hw(wl->hw);
5006 if (ret < 0) {
5007 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005008 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005009 }
5010
5011 wl->mac80211_registered = true;
5012
Eliad Pellerd60080a2010-11-24 12:53:16 +02005013 wl1271_debugfs_init(wl);
5014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005015 wl1271_notice("loaded");
5016
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005017out:
5018 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005019}
5020
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005021static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005022{
Eliad Peller3fcdab72012-02-06 12:47:54 +02005023 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02005024 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005025
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005026 ieee80211_unregister_hw(wl->hw);
5027 wl->mac80211_registered = false;
5028
5029}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005030
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005031static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
5032 {
5033 .max = 2,
5034 .types = BIT(NL80211_IFTYPE_STATION),
5035 },
5036 {
5037 .max = 1,
5038 .types = BIT(NL80211_IFTYPE_AP) |
5039 BIT(NL80211_IFTYPE_P2P_GO) |
5040 BIT(NL80211_IFTYPE_P2P_CLIENT),
5041 },
5042};
5043
5044static const struct ieee80211_iface_combination
5045wlcore_iface_combinations[] = {
5046 {
5047 .num_different_channels = 1,
5048 .max_interfaces = 2,
5049 .limits = wlcore_iface_limits,
5050 .n_limits = ARRAY_SIZE(wlcore_iface_limits),
5051 },
5052};
5053
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005054static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005055{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005056 static const u32 cipher_suites[] = {
5057 WLAN_CIPHER_SUITE_WEP40,
5058 WLAN_CIPHER_SUITE_WEP104,
5059 WLAN_CIPHER_SUITE_TKIP,
5060 WLAN_CIPHER_SUITE_CCMP,
5061 WL1271_CIPHER_SUITE_GEM,
5062 };
5063
Arik Nemtsov2c0133a2012-05-18 07:46:36 +03005064 /* The tx descriptor buffer */
5065 wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
5066
5067 if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
5068 wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005069
5070 /* unit us */
5071 /* FIXME: find a proper value */
5072 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005073 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005074
5075 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005076 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005077 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005078 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005079 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005080 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005081 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005082 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005083 IEEE80211_HW_AP_LINK_PS |
5084 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005085 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
5086 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005087
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005088 wl->hw->wiphy->cipher_suites = cipher_suites;
5089 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5090
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005091 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005092 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5093 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005094 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005095 wl->hw->wiphy->max_sched_scan_ssids = 16;
5096 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005097 /*
5098 * Maximum length of elements in scanning probe request templates
5099 * should be the maximum length possible for a template, without
5100 * the IEEE80211 header of the template
5101 */
Ido Reisc08e3712012-02-02 13:54:27 +02005102 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005103 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005104
Ido Reisc08e3712012-02-02 13:54:27 +02005105 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005106 sizeof(struct ieee80211_header);
5107
Johannes Berg81ddbb52012-03-26 18:47:18 +02005108 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
5109 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
Eliad Peller1ec23f72011-08-25 14:26:54 +03005110
Luciano Coelho4a31c112011-03-21 23:16:14 +02005111 /* make sure all our channels fit in the scanned_ch bitmask */
5112 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5113 ARRAY_SIZE(wl1271_channels_5ghz) >
5114 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005115 /*
5116 * We keep local copies of the band structs because we need to
5117 * modify them on a per-device basis.
5118 */
5119 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5120 sizeof(wl1271_band_2ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005121 memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
5122 &wl->ht_cap[IEEE80211_BAND_2GHZ],
5123 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005124 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5125 sizeof(wl1271_band_5ghz));
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03005126 memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
5127 &wl->ht_cap[IEEE80211_BAND_5GHZ],
5128 sizeof(*wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005129
5130 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5131 &wl->bands[IEEE80211_BAND_2GHZ];
5132 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5133 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005134
Kalle Valo12bd8942010-03-18 12:26:33 +02005135 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005136 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005137
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005138 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5139
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005140 /* the FW answers probe-requests in AP-mode */
5141 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5142 wl->hw->wiphy->probe_resp_offload =
5143 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5144 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5145 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5146
Eliad Pellerbcab320b2012-06-13 20:29:16 +03005147 /* allowed interface combinations */
5148 wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
5149 wl->hw->wiphy->n_iface_combinations =
5150 ARRAY_SIZE(wlcore_iface_combinations);
5151
Felipe Balbia390e852011-10-06 10:07:44 +03005152 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005153
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005154 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005155 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005156
Arik Nemtsovba421f82012-01-06 00:05:51 +02005157 wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size;
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005159 return 0;
5160}
5161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005162#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005163
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005164struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005165{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005166 struct ieee80211_hw *hw;
5167 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005168 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005169 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005170
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005171 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005172
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005173 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5174 if (!hw) {
5175 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005176 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005177 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005178 }
5179
5180 wl = hw->priv;
5181 memset(wl, 0, sizeof(*wl));
5182
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005183 wl->priv = kzalloc(priv_size, GFP_KERNEL);
5184 if (!wl->priv) {
5185 wl1271_error("could not alloc wl priv");
5186 ret = -ENOMEM;
5187 goto err_priv_alloc;
5188 }
5189
Eliad Peller87627212011-10-10 10:12:54 +02005190 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005192 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005193
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005194 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005195 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005196 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5197
Ido Yariva6208652011-03-01 15:14:41 +02005198 skb_queue_head_init(&wl->deferred_rx_queue);
5199 skb_queue_head_init(&wl->deferred_tx_queue);
5200
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005201 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005202 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005203 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5204 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5205 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02005206 INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03005207 INIT_DELAYED_WORK(&wl->connection_loss_work,
5208 wl1271_connection_loss_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005209
Eliad Peller92ef8962011-06-07 12:50:46 +03005210 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5211 if (!wl->freezable_wq) {
5212 ret = -ENOMEM;
5213 goto err_hw;
5214 }
5215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005216 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005217 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005218 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005219 wl->band = IEEE80211_BAND_2GHZ;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03005220 wl->channel_type = NL80211_CHAN_NO_HT;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005221 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005222 wl->sg_enabled = true;
Arik Nemtsov66340e52012-06-10 17:09:22 +03005223 wl->sleep_auth = WL1271_PSM_ILLEGAL;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005224 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005225 wl->ap_ps_map = 0;
5226 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005227 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005228 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005229 wl->sched_scanning = false;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005230 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005231 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005232 wl->fwlog_size = 0;
5233 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005234
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005235 /* The system link is always allocated */
5236 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5237
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005238 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Arik Nemtsov72b06242011-12-07 21:21:51 +02005239 for (i = 0; i < wl->num_tx_desc; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005240 wl->tx_frames[i] = NULL;
5241
5242 spin_lock_init(&wl->wl_lock);
5243
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005244 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005245 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005246 mutex_init(&wl->mutex);
Arik Nemtsov2c388492012-05-18 07:46:39 +03005247 mutex_init(&wl->flush_mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005248
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005249 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5250 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5251 if (!wl->aggr_buf) {
5252 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005253 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005254 }
5255
Ido Yariv990f5de2011-03-31 10:06:59 +02005256 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5257 if (!wl->dummy_packet) {
5258 ret = -ENOMEM;
5259 goto err_aggr;
5260 }
5261
Ido Yariv95dac04f2011-06-06 14:57:06 +03005262 /* Allocate one page for the FW log */
5263 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5264 if (!wl->fwlog) {
5265 ret = -ENOMEM;
5266 goto err_dummy_packet;
5267 }
5268
Luciano Coelhofd492ed2012-05-03 10:31:02 +03005269 wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
Mircea Gherzan690142e2012-03-17 18:41:53 +01005270 if (!wl->mbox) {
5271 ret = -ENOMEM;
5272 goto err_fwlog;
5273 }
5274
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005275 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005276
Mircea Gherzan690142e2012-03-17 18:41:53 +01005277err_fwlog:
5278 free_page((unsigned long)wl->fwlog);
5279
Ido Yariv990f5de2011-03-31 10:06:59 +02005280err_dummy_packet:
5281 dev_kfree_skb(wl->dummy_packet);
5282
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005283err_aggr:
5284 free_pages((unsigned long)wl->aggr_buf, order);
5285
Eliad Peller92ef8962011-06-07 12:50:46 +03005286err_wq:
5287 destroy_workqueue(wl->freezable_wq);
5288
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005289err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005290 wl1271_debugfs_exit(wl);
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005291 kfree(wl->priv);
5292
5293err_priv_alloc:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005294 ieee80211_free_hw(hw);
5295
5296err_hw_alloc:
5297
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005298 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005299}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005300EXPORT_SYMBOL_GPL(wlcore_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005301
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005302int wlcore_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005303{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005304 /* Unblock any fwlog readers */
5305 mutex_lock(&wl->mutex);
5306 wl->fwlog_size = -1;
5307 wake_up_interruptible_all(&wl->fwlog_waitq);
5308 mutex_unlock(&wl->mutex);
5309
Felipe Balbif79f8902011-10-06 13:05:25 +03005310 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005311
Felipe Balbif79f8902011-10-06 13:05:25 +03005312 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005313
Felipe Balbif79f8902011-10-06 13:05:25 +03005314 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005315 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005316 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005317 free_pages((unsigned long)wl->aggr_buf,
5318 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005319
5320 wl1271_debugfs_exit(wl);
5321
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005322 vfree(wl->fw);
5323 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005324 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005325 kfree(wl->nvs);
5326 wl->nvs = NULL;
5327
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03005328 kfree(wl->fw_status_1);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005329 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005330 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005331
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005332 kfree(wl->priv);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005333 ieee80211_free_hw(wl->hw);
5334
5335 return 0;
5336}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005337EXPORT_SYMBOL_GPL(wlcore_free_hw);
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005338
Felipe Balbia390e852011-10-06 10:07:44 +03005339static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5340{
5341 struct wl1271 *wl = cookie;
5342 unsigned long flags;
5343
5344 wl1271_debug(DEBUG_IRQ, "IRQ");
5345
5346 /* complete the ELP completion */
5347 spin_lock_irqsave(&wl->wl_lock, flags);
5348 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5349 if (wl->elp_compl) {
5350 complete(wl->elp_compl);
5351 wl->elp_compl = NULL;
5352 }
5353
5354 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5355 /* don't enqueue a work right now. mark it as pending */
5356 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5357 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5358 disable_irq_nosync(wl->irq);
5359 pm_wakeup_event(wl->dev, 0);
5360 spin_unlock_irqrestore(&wl->wl_lock, flags);
5361 return IRQ_HANDLED;
5362 }
5363 spin_unlock_irqrestore(&wl->wl_lock, flags);
5364
5365 return IRQ_WAKE_THREAD;
5366}
5367
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005368int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03005369{
Felipe Balbia390e852011-10-06 10:07:44 +03005370 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
Felipe Balbia390e852011-10-06 10:07:44 +03005371 unsigned long irqflags;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005372 int ret;
Felipe Balbia390e852011-10-06 10:07:44 +03005373
Luciano Coelho25a43d72011-11-21 20:37:14 +02005374 if (!wl->ops || !wl->ptable) {
Luciano Coelhoc31be252011-11-21 19:25:24 +02005375 ret = -EINVAL;
5376 goto out_free_hw;
Felipe Balbia390e852011-10-06 10:07:44 +03005377 }
5378
Arik Nemtsov72b06242011-12-07 21:21:51 +02005379 BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
5380
Luciano Coelhoe87288f2011-12-05 16:12:54 +02005381 /* adjust some runtime configuration parameters */
5382 wlcore_adjust_conf(wl);
5383
Felipe Balbia390e852011-10-06 10:07:44 +03005384 wl->irq = platform_get_irq(pdev, 0);
Felipe Balbia390e852011-10-06 10:07:44 +03005385 wl->platform_quirks = pdata->platform_quirks;
5386 wl->set_power = pdata->set_power;
5387 wl->dev = &pdev->dev;
5388 wl->if_ops = pdata->ops;
5389
5390 platform_set_drvdata(pdev, wl);
5391
5392 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5393 irqflags = IRQF_TRIGGER_RISING;
5394 else
5395 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5396
5397 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5398 irqflags,
5399 pdev->name, wl);
5400 if (ret < 0) {
5401 wl1271_error("request_irq() failed: %d", ret);
5402 goto out_free_hw;
5403 }
5404
5405 ret = enable_irq_wake(wl->irq);
5406 if (!ret) {
5407 wl->irq_wake_enabled = true;
5408 device_init_wakeup(wl->dev, 1);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02005409 if (pdata->pwr_in_suspend) {
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005410 wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02005411 wl->hw->wiphy->wowlan.n_patterns =
5412 WL1271_MAX_RX_FILTERS;
5413 wl->hw->wiphy->wowlan.pattern_min_len = 1;
5414 wl->hw->wiphy->wowlan.pattern_max_len =
5415 WL1271_RX_FILTER_MAX_PATTERN_SIZE;
5416 }
Felipe Balbia390e852011-10-06 10:07:44 +03005417 }
5418 disable_irq(wl->irq);
5419
Luciano Coelho4afc37a2012-05-10 12:14:02 +03005420 ret = wl12xx_get_hw_info(wl);
5421 if (ret < 0) {
5422 wl1271_error("couldn't get hw info");
5423 goto out;
5424 }
5425
5426 ret = wl->ops->identify_chip(wl);
5427 if (ret < 0)
5428 goto out;
5429
Felipe Balbia390e852011-10-06 10:07:44 +03005430 ret = wl1271_init_ieee80211(wl);
5431 if (ret)
5432 goto out_irq;
5433
5434 ret = wl1271_register_hw(wl);
5435 if (ret)
5436 goto out_irq;
5437
Felipe Balbif79f8902011-10-06 13:05:25 +03005438 /* Create sysfs file to control bt coex state */
5439 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5440 if (ret < 0) {
5441 wl1271_error("failed to create sysfs file bt_coex_state");
5442 goto out_irq;
5443 }
5444
5445 /* Create sysfs file to get HW PG version */
5446 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5447 if (ret < 0) {
5448 wl1271_error("failed to create sysfs file hw_pg_ver");
5449 goto out_bt_coex_state;
5450 }
5451
5452 /* Create sysfs file for the FW log */
5453 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5454 if (ret < 0) {
5455 wl1271_error("failed to create sysfs file fwlog");
5456 goto out_hw_pg_ver;
5457 }
5458
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005459 goto out;
Felipe Balbia390e852011-10-06 10:07:44 +03005460
Felipe Balbif79f8902011-10-06 13:05:25 +03005461out_hw_pg_ver:
5462 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5463
5464out_bt_coex_state:
5465 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5466
Felipe Balbia390e852011-10-06 10:07:44 +03005467out_irq:
5468 free_irq(wl->irq, wl);
5469
5470out_free_hw:
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005471 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03005472
5473out:
5474 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005475}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005476EXPORT_SYMBOL_GPL(wlcore_probe);
Felipe Balbice2a2172011-10-05 14:12:55 +03005477
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005478int __devexit wlcore_remove(struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03005479{
Felipe Balbia390e852011-10-06 10:07:44 +03005480 struct wl1271 *wl = platform_get_drvdata(pdev);
5481
5482 if (wl->irq_wake_enabled) {
5483 device_init_wakeup(wl->dev, 0);
5484 disable_irq_wake(wl->irq);
5485 }
5486 wl1271_unregister_hw(wl);
5487 free_irq(wl->irq, wl);
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005488 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03005489
Felipe Balbice2a2172011-10-05 14:12:55 +03005490 return 0;
5491}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005492EXPORT_SYMBOL_GPL(wlcore_remove);
Felipe Balbice2a2172011-10-05 14:12:55 +03005493
Guy Eilam491bbd62011-01-12 10:33:29 +01005494u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005495EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005496module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005497MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5498
Ido Yariv95dac04f2011-06-06 14:57:06 +03005499module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005500MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005501 "FW logger options: continuous, ondemand, dbgpins or disable");
5502
Eliad Peller2a5bff02011-08-25 18:10:59 +03005503module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5504MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5505
Arik Nemtsov34785be2011-12-08 13:06:45 +02005506module_param(no_recovery, bool, S_IRUSR | S_IWUSR);
5507MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
5508
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005509MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005510MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005511MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");