blob: 1974be0ccd589a27e010251af7ab6a6379af7eb9 [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
Eliad Peller4d56ad92011-08-14 13:17:05 +0300381static void wl12xx_fw_status(struct wl1271 *wl,
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300382 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;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300391
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300392 status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
393 sizeof(*status_2) + wl->fw_status_priv_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300394
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300395 wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
Arik Nemtsov6bac40a2011-12-12 12:08:25 +0200396 status_len, false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200397
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
399 "drv_rx_counter = %d, tx_results_counter = %d)",
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300400 status_1->intr,
401 status_1->fw_rx_counter,
402 status_1->drv_rx_counter,
403 status_1->tx_results_counter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300405 for (i = 0; i < NUM_TX_QUEUES; i++) {
406 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300407 wl->tx_allocated_pkts[i] -=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300408 (status_2->counters.tx_released_pkts[i] -
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300409 wl->tx_pkts_freed[i]) & 0xff;
410
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300411 wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300412 }
413
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300414 /* prevent wrap-around in total blocks counter */
415 if (likely(wl->tx_blocks_freed <=
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300416 le32_to_cpu(status_2->total_released_blks)))
417 freed_blocks = le32_to_cpu(status_2->total_released_blks) -
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300418 wl->tx_blocks_freed;
419 else
420 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300421 le32_to_cpu(status_2->total_released_blks);
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300422
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300423 wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200424
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300425 wl->tx_allocated_blocks -= freed_blocks;
426
Arik Nemtsov55df5af2012-03-03 22:18:00 +0200427 /*
428 * If the FW freed some blocks:
429 * If we still have allocated blocks - re-arm the timer, Tx is
430 * not stuck. Otherwise, cancel the timer (no Tx currently).
431 */
432 if (freed_blocks) {
433 if (wl->tx_allocated_blocks)
434 wl12xx_rearm_tx_watchdog_locked(wl);
435 else
436 cancel_delayed_work(&wl->tx_watchdog_work);
437 }
438
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300439 avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200440
Eliad Peller4d56ad92011-08-14 13:17:05 +0300441 /*
442 * The FW might change the total number of TX memblocks before
443 * we get a notification about blocks being released. Thus, the
444 * available blocks calculation might yield a temporary result
445 * which is lower than the actual available blocks. Keeping in
446 * mind that only blocks that were allocated can be moved from
447 * TX to RX, tx_blocks_available should never decrease here.
448 */
449 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
450 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300451
Ido Yariva5225502010-10-12 14:49:10 +0200452 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200453 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200454 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455
Eliad Peller4d56ad92011-08-14 13:17:05 +0300456 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200457 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300458 wl12xx_irq_update_links_status(wl, wlvif, status_2);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200459 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200462 getnstimeofday(&ts);
463 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300464 (s64)le32_to_cpu(status_2->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465}
466
Ido Yariva6208652011-03-01 15:14:41 +0200467static void wl1271_flush_deferred_work(struct wl1271 *wl)
468{
469 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200470
Ido Yariva6208652011-03-01 15:14:41 +0200471 /* Pass all received frames to the network stack */
472 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
473 ieee80211_rx_ni(wl->hw, skb);
474
475 /* Return sent skbs to the network stack */
476 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300477 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200478}
479
480static void wl1271_netstack_work(struct work_struct *work)
481{
482 struct wl1271 *wl =
483 container_of(work, struct wl1271, netstack_work);
484
485 do {
486 wl1271_flush_deferred_work(wl);
487 } while (skb_queue_len(&wl->deferred_rx_queue));
488}
489
490#define WL1271_IRQ_MAX_LOOPS 256
491
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300492static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300494 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300495 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200496 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200497 struct wl1271 *wl = (struct wl1271 *)cookie;
498 bool done = false;
499 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200500 unsigned long flags;
501
502 /* TX might be handled here, avoid redundant work */
503 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
504 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505
Ido Yariv341b7cd2011-03-31 10:07:01 +0200506 /*
507 * In case edge triggered interrupt must be used, we cannot iterate
508 * more than once without introducing race conditions with the hardirq.
509 */
510 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
511 loopcount = 1;
512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513 mutex_lock(&wl->mutex);
514
515 wl1271_debug(DEBUG_IRQ, "IRQ work");
516
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200517 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 goto out;
519
Ido Yariva6208652011-03-01 15:14:41 +0200520 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521 if (ret < 0)
522 goto out;
523
Ido Yariva6208652011-03-01 15:14:41 +0200524 while (!done && loopcount--) {
525 /*
526 * In order to avoid a race with the hardirq, clear the flag
527 * before acknowledging the chip. Since the mutex is held,
528 * wl1271_ps_elp_wakeup cannot be called concurrently.
529 */
530 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
531 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200532
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300533 wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
Arik Nemtsov53d67a52011-12-12 11:32:37 +0200534
535 wlcore_hw_tx_immediate_compl(wl);
536
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300537 intr = le32_to_cpu(wl->fw_status_1->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200538 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200539 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200540 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200541 continue;
542 }
543
Eliad Pellerccc83b02010-10-27 14:09:57 +0200544 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
545 wl1271_error("watchdog interrupt received! "
546 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300547 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200548
549 /* restarting the chip. ignore any other interrupt. */
550 goto out;
551 }
552
Ido Yariva6208652011-03-01 15:14:41 +0200553 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200554 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
555
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300556 wl12xx_rx(wl, wl->fw_status_1);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200557
Ido Yariva5225502010-10-12 14:49:10 +0200558 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200559 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200560 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300561 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200562 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200563 /*
564 * In order to avoid starvation of the TX path,
565 * call the work function directly.
566 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200567 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200568 } else {
569 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200570 }
571
Ido Yariv8aad2462011-03-01 15:14:38 +0200572 /* check for tx results */
Arik Nemtsov53d67a52011-12-12 11:32:37 +0200573 wlcore_hw_tx_delayed_compl(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200574
575 /* Make sure the deferred queues don't get too long */
576 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
577 skb_queue_len(&wl->deferred_rx_queue);
578 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
579 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200580 }
581
582 if (intr & WL1271_ACX_INTR_EVENT_A) {
583 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
584 wl1271_event_handle(wl, 0);
585 }
586
587 if (intr & WL1271_ACX_INTR_EVENT_B) {
588 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
589 wl1271_event_handle(wl, 1);
590 }
591
592 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
593 wl1271_debug(DEBUG_IRQ,
594 "WL1271_ACX_INTR_INIT_COMPLETE");
595
596 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
597 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300598 }
599
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600 wl1271_ps_elp_sleep(wl);
601
602out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200603 spin_lock_irqsave(&wl->wl_lock, flags);
604 /* In case TX was not handled here, queue TX work */
605 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
606 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300607 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200608 ieee80211_queue_work(wl->hw, &wl->tx_work);
609 spin_unlock_irqrestore(&wl->wl_lock, flags);
610
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200612
613 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300614}
615
Eliad Peller4549d092012-02-06 13:07:52 +0200616struct vif_counter_data {
617 u8 counter;
618
619 struct ieee80211_vif *cur_vif;
620 bool cur_vif_running;
621};
622
623static void wl12xx_vif_count_iter(void *data, u8 *mac,
624 struct ieee80211_vif *vif)
625{
626 struct vif_counter_data *counter = data;
627
628 counter->counter++;
629 if (counter->cur_vif == vif)
630 counter->cur_vif_running = true;
631}
632
633/* caller must not hold wl->mutex, as it might deadlock */
634static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
635 struct ieee80211_vif *cur_vif,
636 struct vif_counter_data *data)
637{
638 memset(data, 0, sizeof(*data));
639 data->cur_vif = cur_vif;
640
641 ieee80211_iterate_active_interfaces(hw,
642 wl12xx_vif_count_iter, data);
643}
644
Eliad Peller3fcdab72012-02-06 12:47:54 +0200645static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646{
647 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200648 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200649 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650 int ret;
651
Eliad Peller3fcdab72012-02-06 12:47:54 +0200652 if (plt) {
653 fw_type = WL12XX_FW_TYPE_PLT;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200654 fw_name = wl->plt_fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200655 } else {
Eliad Peller4549d092012-02-06 13:07:52 +0200656 /*
657 * we can't call wl12xx_get_vif_count() here because
658 * wl->mutex is taken, so use the cached last_vif_count value
659 */
660 if (wl->last_vif_count > 1) {
661 fw_type = WL12XX_FW_TYPE_MULTI;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200662 fw_name = wl->mr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200663 } else {
664 fw_type = WL12XX_FW_TYPE_NORMAL;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200665 fw_name = wl->sr_fw_name;
Eliad Peller4549d092012-02-06 13:07:52 +0200666 }
Eliad Peller3fcdab72012-02-06 12:47:54 +0200667 }
668
669 if (wl->fw_type == fw_type)
670 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200671
672 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
673
Felipe Balbia390e852011-10-06 10:07:44 +0300674 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675
676 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100677 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 return ret;
679 }
680
681 if (fw->size % 4) {
682 wl1271_error("firmware size is not multiple of 32 bits: %zu",
683 fw->size);
684 ret = -EILSEQ;
685 goto out;
686 }
687
Arik Nemtsov166d5042010-10-16 21:44:57 +0200688 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +0200689 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300691 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692
693 if (!wl->fw) {
694 wl1271_error("could not allocate memory for the firmware");
695 ret = -ENOMEM;
696 goto out;
697 }
698
699 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 ret = 0;
Eliad Peller3fcdab72012-02-06 12:47:54 +0200701 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702out:
703 release_firmware(fw);
704
705 return ret;
706}
707
708static int wl1271_fetch_nvs(struct wl1271 *wl)
709{
710 const struct firmware *fw;
711 int ret;
712
Felipe Balbia390e852011-10-06 10:07:44 +0300713 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714
715 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100716 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
717 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718 return ret;
719 }
720
Shahar Levibc765bf2011-03-06 16:32:10 +0200721 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722
723 if (!wl->nvs) {
724 wl1271_error("could not allocate memory for the nvs file");
725 ret = -ENOMEM;
726 goto out;
727 }
728
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200729 wl->nvs_len = fw->size;
730
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731out:
732 release_firmware(fw);
733
734 return ret;
735}
736
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300737void wl12xx_queue_recovery_work(struct wl1271 *wl)
738{
739 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
740 ieee80211_queue_work(wl->hw, &wl->recovery_work);
741}
742
Ido Yariv95dac04f2011-06-06 14:57:06 +0300743size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
744{
745 size_t len = 0;
746
747 /* The FW log is a length-value list, find where the log end */
748 while (len < maxlen) {
749 if (memblock[len] == 0)
750 break;
751 if (len + memblock[len] + 1 > maxlen)
752 break;
753 len += memblock[len] + 1;
754 }
755
756 /* Make sure we have enough room */
757 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
758
759 /* Fill the FW log file, consumed by the sysfs fwlog entry */
760 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
761 wl->fwlog_size += len;
762
763 return len;
764}
765
766static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
767{
768 u32 addr;
769 u32 first_addr;
770 u8 *block;
771
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200772 if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
Ido Yariv95dac04f2011-06-06 14:57:06 +0300773 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
774 (wl->conf.fwlog.mem_blocks == 0))
775 return;
776
777 wl1271_info("Reading FW panic log");
778
779 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
780 if (!block)
781 return;
782
783 /*
784 * Make sure the chip is awake and the logger isn't active.
785 * This might fail if the firmware hanged.
786 */
787 if (!wl1271_ps_elp_wakeup(wl))
788 wl12xx_cmd_stop_fwlog(wl);
789
790 /* Read the first memory block address */
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300791 wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
792 first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +0300793 if (!first_addr)
794 goto out;
795
796 /* Traverse the memory blocks linked list */
797 addr = first_addr;
798 do {
799 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
800 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
801 false);
802
803 /*
804 * Memory blocks are linked to one another. The first 4 bytes
805 * of each memory block hold the hardware address of the next
806 * one. The last memory block points to the first one.
807 */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +0300809 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
810 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
811 break;
812 } while (addr && (addr != first_addr));
813
814 wake_up_interruptible(&wl->fwlog_waitq);
815
816out:
817 kfree(block);
818}
819
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200820static void wl1271_recovery_work(struct work_struct *work)
821{
822 struct wl1271 *wl =
823 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +0200824 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +0200825 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200826
827 mutex_lock(&wl->mutex);
828
Eliad Peller3fcdab72012-02-06 12:47:54 +0200829 if (wl->state != WL1271_STATE_ON || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +0200830 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200831
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300832 /* Avoid a recursive recovery */
833 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
834
Ido Yariv95dac04f2011-06-06 14:57:06 +0300835 wl12xx_read_fwlog_panic(wl);
836
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300837 /* change partitions momentarily so we can read the FW pc */
838 wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Luciano Coelho06bba802012-05-10 12:14:12 +0300839 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
840 "hint_sts: 0x%08x",
Luciano Coelho00782132011-11-29 13:38:37 +0200841 wl->chip.fw_ver_str,
Luciano Coelho06bba802012-05-10 12:14:12 +0300842 wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
843 wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300844 wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200845
Eliad Pellere9ba7152012-03-04 10:55:54 +0200846 BUG_ON(bug_on_recovery &&
847 !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
Eliad Peller2a5bff02011-08-25 18:10:59 +0300848
Arik Nemtsov34785be2011-12-08 13:06:45 +0200849 if (no_recovery) {
850 wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
851 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
852 goto out_unlock;
853 }
854
855 BUG_ON(bug_on_recovery);
856
Oz Krakowskib992c682011-06-26 10:36:02 +0300857 /*
858 * Advance security sequence number to overcome potential progress
859 * in the firmware during recovery. This doens't hurt if the network is
860 * not encrypted.
861 */
Eliad Peller48e93e42011-10-10 10:12:58 +0200862 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +0200863 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +0200864 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +0200865 wlvif->tx_security_seq +=
866 WL1271_TX_SQN_POST_RECOVERY_PADDING;
867 }
Oz Krakowskib992c682011-06-26 10:36:02 +0300868
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300869 /* Prevent spurious TX during FW restart */
870 ieee80211_stop_queues(wl->hw);
871
Luciano Coelho33c2c062011-05-10 14:46:02 +0300872 if (wl->sched_scanning) {
873 ieee80211_sched_scan_stopped(wl->hw);
874 wl->sched_scanning = false;
875 }
876
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200877 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200878 while (!list_empty(&wl->wlvif_list)) {
879 wlvif = list_first_entry(&wl->wlvif_list,
880 struct wl12xx_vif, list);
881 vif = wl12xx_wlvif_to_vif(wlvif);
882 __wl1271_op_remove_interface(wl, vif, false);
883 }
Eliad Pellerf0277432011-10-10 10:13:14 +0200884 mutex_unlock(&wl->mutex);
885 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300886
887 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
888
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200889 ieee80211_restart_hw(wl->hw);
890
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300891 /*
892 * Its safe to enable TX now - the queues are stopped after a request
893 * to restart the HW.
894 */
895 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +0200896 return;
897out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200898 mutex_unlock(&wl->mutex);
899}
900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901static void wl1271_fw_wakeup(struct wl1271 *wl)
902{
Luciano Coelho00782132011-11-29 13:38:37 +0200903 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904}
905
906static int wl1271_setup(struct wl1271 *wl)
907{
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300908 wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
Luciano Coelho4f64a1e2012-05-10 12:14:00 +0300909 sizeof(*wl->fw_status_2) +
910 wl->fw_status_priv_len, GFP_KERNEL);
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300911 if (!wl->fw_status_1)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912 return -ENOMEM;
913
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300914 wl->fw_status_2 = (struct wl_fw_status_2 *)
915 (((u8 *) wl->fw_status_1) +
916 WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
917
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
919 if (!wl->tx_res_if) {
Arik Nemtsov0afd04e2012-05-10 12:13:54 +0300920 kfree(wl->fw_status_1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 return -ENOMEM;
922 }
923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924 return 0;
925}
926
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200927static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200929 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200931 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200932 ret = wl1271_power_on(wl);
933 if (ret < 0)
934 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200936 wl1271_io_reset(wl);
937 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938
Luciano Coelho00782132011-11-29 13:38:37 +0200939 wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
941 /* ELP module wake up */
942 wl1271_fw_wakeup(wl);
943
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200944out:
945 return ret;
946}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947
Eliad Peller3fcdab72012-02-06 12:47:54 +0200948static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +0200949{
950 int ret = 0;
951
952 ret = wl12xx_set_power_on(wl);
953 if (ret < 0)
954 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +0200956 /*
957 * For wl127x based devices we could use the default block
958 * size (512 bytes), but due to a bug in the sdio driver, we
959 * need to set it explicitly after the chip is powered on. To
960 * simplify the code and since the performance impact is
961 * negligible, we use the same block size for all different
962 * chip types.
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300963 *
964 * Check if the bus supports blocksize alignment and, if it
965 * doesn't, make sure we don't have the quirk.
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +0200966 */
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300967 if (!wl1271_set_block_size(wl))
968 wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200970 /* TODO: make sure the lower driver has set things up correctly */
971
972 ret = wl1271_setup(wl);
973 if (ret < 0)
974 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975
Eliad Peller3fcdab72012-02-06 12:47:54 +0200976 ret = wl12xx_fetch_firmware(wl, plt);
977 if (ret < 0)
978 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
980 /* No NVS from netlink, try to get it from the filesystem */
981 if (wl->nvs == NULL) {
982 ret = wl1271_fetch_nvs(wl);
983 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200984 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 }
986
987out:
988 return ret;
989}
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991int wl1271_plt_start(struct wl1271 *wl)
992{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200993 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +0300994 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 int ret;
996
997 mutex_lock(&wl->mutex);
998
999 wl1271_notice("power up");
1000
1001 if (wl->state != WL1271_STATE_OFF) {
1002 wl1271_error("cannot go into PLT state because not "
1003 "in off state: %d", wl->state);
1004 ret = -EBUSY;
1005 goto out;
1006 }
1007
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 while (retries) {
1009 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001010 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001011 if (ret < 0)
1012 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
Luciano Coelhoc331b342012-05-10 12:13:49 +03001014 ret = wl->ops->plt_init(wl);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001015 if (ret < 0)
1016 goto power_off;
1017
Eliad Peller3fcdab72012-02-06 12:47:54 +02001018 wl->plt = true;
1019 wl->state = WL1271_STATE_ON;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001020 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001021 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001022
Gery Kahn6f07b722011-07-18 14:21:49 +03001023 /* update hw/fw version info in wiphy struct */
1024 wiphy->hw_version = wl->chip.id;
1025 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1026 sizeof(wiphy->fw_version));
1027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 goto out;
1029
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001030power_off:
1031 wl1271_power_off(wl);
1032 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001034 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1035 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036out:
1037 mutex_unlock(&wl->mutex);
1038
1039 return ret;
1040}
1041
Ido Yarivf3df1332012-01-11 09:42:39 +02001042int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043{
1044 int ret = 0;
1045
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 wl1271_notice("power down");
1047
Ido Yariv46b0cc92012-01-11 09:42:41 +02001048 /*
1049 * Interrupts must be disabled before setting the state to OFF.
1050 * Otherwise, the interrupt handler might be called and exit without
1051 * reading the interrupt status.
1052 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001053 wlcore_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001054 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001055 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001056 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001057
1058 /*
1059 * This will not necessarily enable interrupts as interrupts
1060 * may have been disabled when op_stop was called. It will,
1061 * however, balance the above call to disable_interrupts().
1062 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001063 wlcore_enable_interrupts(wl);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065 wl1271_error("cannot power down because not in PLT "
1066 "state: %d", wl->state);
1067 ret = -EBUSY;
1068 goto out;
1069 }
1070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001072
Ido Yariva6208652011-03-01 15:14:41 +02001073 wl1271_flush_deferred_work(wl);
1074 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001075 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001076 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001077 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03001078 cancel_delayed_work_sync(&wl->connection_loss_work);
Ido Yariva4549692012-01-11 09:42:40 +02001079
1080 mutex_lock(&wl->mutex);
1081 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001082 wl->flags = 0;
1083 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001084 wl->plt = false;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001085 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001086 mutex_unlock(&wl->mutex);
1087
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001088out:
1089 return ret;
1090}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001091
Johannes Berg7bb45682011-02-24 14:42:06 +01001092static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093{
1094 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001095 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1096 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001097 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001098 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001099 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001100 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
Eliad Peller0f168012011-10-11 13:52:25 +02001102 if (vif)
1103 wlvif = wl12xx_vif_to_data(vif);
1104
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001105 mapping = skb_get_queue_mapping(skb);
1106 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001107
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001108 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001109
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001110 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001111
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001112 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001113 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001114 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001115 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001116 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001117 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001118 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119
Eliad Peller8ccd16e2012-03-04 10:55:55 +02001120 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d",
1121 hlid, q, skb->len);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001122 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1123
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001124 wl->tx_queue_count[q]++;
1125
1126 /*
1127 * The workqueue is slow to process the tx_queue and we need stop
1128 * the queue here, otherwise the queue will get too long.
1129 */
1130 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1131 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1132 ieee80211_stop_queue(wl->hw, mapping);
1133 set_bit(q, &wl->stopped_queues_map);
1134 }
1135
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136 /*
1137 * The chip specific setup must run before the first TX packet -
1138 * before that, the tx_work will not be initialized!
1139 */
1140
Ido Yarivb07d4032011-03-01 15:14:43 +02001141 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1142 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001143 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001144
Arik Nemtsov04216da2011-08-14 13:17:38 +03001145out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001146 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147}
1148
Shahar Leviae47c452011-03-06 16:32:14 +02001149int wl1271_tx_dummy_packet(struct wl1271 *wl)
1150{
Ido Yariv990f5de2011-03-31 10:06:59 +02001151 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001152 int q;
1153
1154 /* no need to queue a new dummy packet if one is already pending */
1155 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1156 return 0;
1157
1158 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001159
Ido Yariv990f5de2011-03-31 10:06:59 +02001160 spin_lock_irqsave(&wl->wl_lock, flags);
1161 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001162 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001163 spin_unlock_irqrestore(&wl->wl_lock, flags);
1164
1165 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1166 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001167 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001168
1169 /*
1170 * If the FW TX is busy, TX work will be scheduled by the threaded
1171 * interrupt handler function
1172 */
1173 return 0;
1174}
1175
1176/*
1177 * The size of the dummy packet should be at least 1400 bytes. However, in
1178 * order to minimize the number of bus transactions, aligning it to 512 bytes
1179 * boundaries could be beneficial, performance wise
1180 */
1181#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1182
Luciano Coelhocf27d862011-04-01 21:08:23 +03001183static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001184{
1185 struct sk_buff *skb;
1186 struct ieee80211_hdr_3addr *hdr;
1187 unsigned int dummy_packet_size;
1188
1189 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1190 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1191
1192 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001193 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001194 wl1271_warning("Failed to allocate a dummy packet skb");
1195 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001196 }
1197
1198 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1199
1200 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1201 memset(hdr, 0, sizeof(*hdr));
1202 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001203 IEEE80211_STYPE_NULLFUNC |
1204 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001205
Ido Yariv990f5de2011-03-31 10:06:59 +02001206 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001207
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001208 /* Dummy packets require the TID to be management */
1209 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001210
1211 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001212 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001213 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001214
Ido Yariv990f5de2011-03-31 10:06:59 +02001215 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001216}
1217
Ido Yariv990f5de2011-03-31 10:06:59 +02001218
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001219#ifdef CONFIG_PM
Luciano Coelho22479972012-05-16 06:00:00 +03001220static int
1221wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001222{
1223 int num_fields = 0, in_field = 0, fields_size = 0;
1224 int i, pattern_len = 0;
1225
1226 if (!p->mask) {
1227 wl1271_warning("No mask in WoWLAN pattern");
1228 return -EINVAL;
1229 }
1230
1231 /*
1232 * The pattern is broken up into segments of bytes at different offsets
1233 * that need to be checked by the FW filter. Each segment is called
1234 * a field in the FW API. We verify that the total number of fields
1235 * required for this pattern won't exceed FW limits (8)
1236 * as well as the total fields buffer won't exceed the FW limit.
1237 * Note that if there's a pattern which crosses Ethernet/IP header
1238 * boundary a new field is required.
1239 */
1240 for (i = 0; i < p->pattern_len; i++) {
1241 if (test_bit(i, (unsigned long *)p->mask)) {
1242 if (!in_field) {
1243 in_field = 1;
1244 pattern_len = 1;
1245 } else {
1246 if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1247 num_fields++;
1248 fields_size += pattern_len +
1249 RX_FILTER_FIELD_OVERHEAD;
1250 pattern_len = 1;
1251 } else
1252 pattern_len++;
1253 }
1254 } else {
1255 if (in_field) {
1256 in_field = 0;
1257 fields_size += pattern_len +
1258 RX_FILTER_FIELD_OVERHEAD;
1259 num_fields++;
1260 }
1261 }
1262 }
1263
1264 if (in_field) {
1265 fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
1266 num_fields++;
1267 }
1268
1269 if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
1270 wl1271_warning("RX Filter too complex. Too many segments");
1271 return -EINVAL;
1272 }
1273
1274 if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
1275 wl1271_warning("RX filter pattern is too big");
1276 return -E2BIG;
1277 }
1278
1279 return 0;
1280}
1281
Eyal Shapiraa6eab0c2012-03-14 06:32:07 +02001282struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
1283{
1284 return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
1285}
1286
1287void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
1288{
1289 int i;
1290
1291 if (filter == NULL)
1292 return;
1293
1294 for (i = 0; i < filter->num_fields; i++)
1295 kfree(filter->fields[i].pattern);
1296
1297 kfree(filter);
1298}
1299
1300int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
1301 u16 offset, u8 flags,
1302 u8 *pattern, u8 len)
1303{
1304 struct wl12xx_rx_filter_field *field;
1305
1306 if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
1307 wl1271_warning("Max fields per RX filter. can't alloc another");
1308 return -EINVAL;
1309 }
1310
1311 field = &filter->fields[filter->num_fields];
1312
1313 field->pattern = kzalloc(len, GFP_KERNEL);
1314 if (!field->pattern) {
1315 wl1271_warning("Failed to allocate RX filter pattern");
1316 return -ENOMEM;
1317 }
1318
1319 filter->num_fields++;
1320
1321 field->offset = cpu_to_le16(offset);
1322 field->flags = flags;
1323 field->len = len;
1324 memcpy(field->pattern, pattern, len);
1325
1326 return 0;
1327}
1328
1329int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
1330{
1331 int i, fields_size = 0;
1332
1333 for (i = 0; i < filter->num_fields; i++)
1334 fields_size += filter->fields[i].len +
1335 sizeof(struct wl12xx_rx_filter_field) -
1336 sizeof(u8 *);
1337
1338 return fields_size;
1339}
1340
1341void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
1342 u8 *buf)
1343{
1344 int i;
1345 struct wl12xx_rx_filter_field *field;
1346
1347 for (i = 0; i < filter->num_fields; i++) {
1348 field = (struct wl12xx_rx_filter_field *)buf;
1349
1350 field->offset = filter->fields[i].offset;
1351 field->flags = filter->fields[i].flags;
1352 field->len = filter->fields[i].len;
1353
1354 memcpy(&field->pattern, filter->fields[i].pattern, field->len);
1355 buf += sizeof(struct wl12xx_rx_filter_field) -
1356 sizeof(u8 *) + field->len;
1357 }
1358}
1359
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001360/*
1361 * Allocates an RX filter returned through f
1362 * which needs to be freed using rx_filter_free()
1363 */
Luciano Coelho22479972012-05-16 06:00:00 +03001364static int wl1271_convert_wowlan_pattern_to_rx_filter(
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001365 struct cfg80211_wowlan_trig_pkt_pattern *p,
1366 struct wl12xx_rx_filter **f)
1367{
1368 int i, j, ret = 0;
1369 struct wl12xx_rx_filter *filter;
1370 u16 offset;
1371 u8 flags, len;
1372
1373 filter = wl1271_rx_filter_alloc();
1374 if (!filter) {
1375 wl1271_warning("Failed to alloc rx filter");
1376 ret = -ENOMEM;
1377 goto err;
1378 }
1379
1380 i = 0;
1381 while (i < p->pattern_len) {
1382 if (!test_bit(i, (unsigned long *)p->mask)) {
1383 i++;
1384 continue;
1385 }
1386
1387 for (j = i; j < p->pattern_len; j++) {
1388 if (!test_bit(j, (unsigned long *)p->mask))
1389 break;
1390
1391 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
1392 j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
1393 break;
1394 }
1395
1396 if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
1397 offset = i;
1398 flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
1399 } else {
1400 offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
1401 flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
1402 }
1403
1404 len = j - i;
1405
1406 ret = wl1271_rx_filter_alloc_field(filter,
1407 offset,
1408 flags,
1409 &p->pattern[i], len);
1410 if (ret)
1411 goto err;
1412
1413 i = j;
1414 }
1415
1416 filter->action = FILTER_SIGNAL;
1417
1418 *f = filter;
1419 return 0;
1420
1421err:
1422 wl1271_rx_filter_free(filter);
1423 *f = NULL;
1424
1425 return ret;
1426}
1427
1428static int wl1271_configure_wowlan(struct wl1271 *wl,
1429 struct cfg80211_wowlan *wow)
1430{
1431 int i, ret;
1432
1433 if (!wow || wow->any || !wow->n_patterns) {
1434 wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1435 wl1271_rx_filter_clear_all(wl);
1436 return 0;
1437 }
1438
1439 if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
1440 return -EINVAL;
1441
1442 /* Validate all incoming patterns before clearing current FW state */
1443 for (i = 0; i < wow->n_patterns; i++) {
1444 ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
1445 if (ret) {
1446 wl1271_warning("Bad wowlan pattern %d", i);
1447 return ret;
1448 }
1449 }
1450
1451 wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
1452 wl1271_rx_filter_clear_all(wl);
1453
1454 /* Translate WoWLAN patterns into filters */
1455 for (i = 0; i < wow->n_patterns; i++) {
1456 struct cfg80211_wowlan_trig_pkt_pattern *p;
1457 struct wl12xx_rx_filter *filter = NULL;
1458
1459 p = &wow->patterns[i];
1460
1461 ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
1462 if (ret) {
1463 wl1271_warning("Failed to create an RX filter from "
1464 "wowlan pattern %d", i);
1465 goto out;
1466 }
1467
1468 ret = wl1271_rx_filter_enable(wl, i, 1, filter);
1469
1470 wl1271_rx_filter_free(filter);
1471 if (ret)
1472 goto out;
1473 }
1474
1475 ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
1476
1477out:
1478 return ret;
1479}
1480
Eyal Shapiradae728f2012-02-02 12:03:39 +02001481static int wl1271_configure_suspend_sta(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001482 struct wl12xx_vif *wlvif,
1483 struct cfg80211_wowlan *wow)
Eyal Shapiradae728f2012-02-02 12:03:39 +02001484{
1485 int ret = 0;
1486
Eyal Shapiradae728f2012-02-02 12:03:39 +02001487 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001488 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001489
1490 ret = wl1271_ps_elp_wakeup(wl);
1491 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001492 goto out;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001493
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001494 wl1271_configure_wowlan(wl, wow);
Eyal Shapiradae728f2012-02-02 12:03:39 +02001495 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1496 wl->conf.conn.suspend_wake_up_event,
1497 wl->conf.conn.suspend_listen_interval);
1498
1499 if (ret < 0)
1500 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1501
Eyal Shapiradae728f2012-02-02 12:03:39 +02001502 wl1271_ps_elp_sleep(wl);
1503
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001504out:
Eyal Shapiradae728f2012-02-02 12:03:39 +02001505 return ret;
1506
1507}
Eliad Peller94390642011-05-13 11:57:13 +03001508
Eliad Peller0603d892011-10-05 11:55:51 +02001509static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1510 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001511{
Eliad Pellere85d1622011-06-27 13:06:43 +03001512 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001513
Eliad Peller53d40d02011-10-10 10:13:02 +02001514 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001515 goto out;
Eliad Pellere85d1622011-06-27 13:06:43 +03001516
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001517 ret = wl1271_ps_elp_wakeup(wl);
1518 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001519 goto out;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001520
Eliad Peller0603d892011-10-05 11:55:51 +02001521 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001522
1523 wl1271_ps_elp_sleep(wl);
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001524out:
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001525 return ret;
1526
1527}
1528
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001529static int wl1271_configure_suspend(struct wl1271 *wl,
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001530 struct wl12xx_vif *wlvif,
1531 struct cfg80211_wowlan *wow)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001532{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001533 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001534 return wl1271_configure_suspend_sta(wl, wlvif, wow);
Eliad Peller536129c2011-10-05 11:55:45 +02001535 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001536 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001537 return 0;
1538}
1539
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001540static void wl1271_configure_resume(struct wl1271 *wl,
1541 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001542{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001543 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001544 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001545 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001546
Eyal Shapiradae728f2012-02-02 12:03:39 +02001547 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001548 return;
1549
Eliad Peller94390642011-05-13 11:57:13 +03001550 ret = wl1271_ps_elp_wakeup(wl);
1551 if (ret < 0)
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001552 return;
Eliad Peller94390642011-05-13 11:57:13 +03001553
Eyal Shapiradae728f2012-02-02 12:03:39 +02001554 if (is_sta) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001555 wl1271_configure_wowlan(wl, NULL);
1556
Eyal Shapiradae728f2012-02-02 12:03:39 +02001557 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1558 wl->conf.conn.wake_up_event,
1559 wl->conf.conn.listen_interval);
1560
1561 if (ret < 0)
1562 wl1271_error("resume: wake up conditions failed: %d",
1563 ret);
1564
1565 } else if (is_ap) {
1566 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1567 }
Eliad Peller94390642011-05-13 11:57:13 +03001568
1569 wl1271_ps_elp_sleep(wl);
Eliad Peller94390642011-05-13 11:57:13 +03001570}
1571
Eliad Peller402e48612011-05-13 11:57:09 +03001572static int wl1271_op_suspend(struct ieee80211_hw *hw,
1573 struct cfg80211_wowlan *wow)
1574{
1575 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001576 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001577 int ret;
1578
Eliad Peller402e48612011-05-13 11:57:09 +03001579 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001580 WARN_ON(!wow);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001581
Arik Nemtsovb9239b62012-02-28 00:41:33 +02001582 wl1271_tx_flush(wl);
1583
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001584 mutex_lock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001585 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001586 wl12xx_for_each_wlvif(wl, wlvif) {
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02001587 ret = wl1271_configure_suspend(wl, wlvif, wow);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001588 if (ret < 0) {
Dan Carpentercd840f62012-04-16 13:57:02 +03001589 mutex_unlock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001590 wl1271_warning("couldn't prepare device to suspend");
1591 return ret;
1592 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001593 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001594 mutex_unlock(&wl->mutex);
Eliad Peller4a859df2011-06-06 12:21:52 +03001595 /* flush any remaining work */
1596 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001597
1598 /*
1599 * disable and re-enable interrupts in order to flush
1600 * the threaded_irq
1601 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001602 wlcore_disable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001603
1604 /*
1605 * set suspended flag to avoid triggering a new threaded_irq
1606 * work. no need for spinlock as interrupts are disabled.
1607 */
1608 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1609
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001610 wlcore_enable_interrupts(wl);
Eliad Peller4a859df2011-06-06 12:21:52 +03001611 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001612 flush_delayed_work(&wl->elp_work);
1613
Eliad Peller402e48612011-05-13 11:57:09 +03001614 return 0;
1615}
1616
1617static int wl1271_op_resume(struct ieee80211_hw *hw)
1618{
1619 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001620 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001621 unsigned long flags;
1622 bool run_irq_work = false;
1623
Eliad Peller402e48612011-05-13 11:57:09 +03001624 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1625 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001626 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001627
1628 /*
1629 * re-enable irq_work enqueuing, and call irq_work directly if
1630 * there is a pending work.
1631 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001632 spin_lock_irqsave(&wl->wl_lock, flags);
1633 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1634 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1635 run_irq_work = true;
1636 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001637
Eliad Peller4a859df2011-06-06 12:21:52 +03001638 if (run_irq_work) {
1639 wl1271_debug(DEBUG_MAC80211,
1640 "run postponed irq_work directly");
1641 wl1271_irq(0, wl);
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001642 wlcore_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001643 }
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001644
1645 mutex_lock(&wl->mutex);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001646 wl12xx_for_each_wlvif(wl, wlvif) {
1647 wl1271_configure_resume(wl, wlvif);
1648 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001649 wl->wow_enabled = false;
Eyal Shapirac56dbd52012-03-13 20:03:21 +02001650 mutex_unlock(&wl->mutex);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001651
Eliad Peller402e48612011-05-13 11:57:09 +03001652 return 0;
1653}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001654#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656static int wl1271_op_start(struct ieee80211_hw *hw)
1657{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001658 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1659
1660 /*
1661 * We have to delay the booting of the hardware because
1662 * we need to know the local MAC address before downloading and
1663 * initializing the firmware. The MAC address cannot be changed
1664 * after boot, and without the proper MAC address, the firmware
1665 * will not function properly.
1666 *
1667 * The MAC address is first known when the corresponding interface
1668 * is added. That is where we will initialize the hardware.
1669 */
1670
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001671 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001672}
1673
1674static void wl1271_op_stop(struct ieee80211_hw *hw)
1675{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001676 struct wl1271 *wl = hw->priv;
1677 int i;
1678
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001679 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001680
Ido Yariv46b0cc92012-01-11 09:42:41 +02001681 /*
1682 * Interrupts must be disabled before setting the state to OFF.
1683 * Otherwise, the interrupt handler might be called and exit without
1684 * reading the interrupt status.
1685 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001686 wlcore_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001687 mutex_lock(&wl->mutex);
1688 if (wl->state == WL1271_STATE_OFF) {
1689 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001690
1691 /*
1692 * This will not necessarily enable interrupts as interrupts
1693 * may have been disabled when op_stop was called. It will,
1694 * however, balance the above call to disable_interrupts().
1695 */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001696 wlcore_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001697 return;
1698 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001699
Eliad Pellerbaf62772011-10-10 10:12:52 +02001700 /*
1701 * this must be before the cancel_work calls below, so that the work
1702 * functions don't perform further work.
1703 */
1704 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001705 mutex_unlock(&wl->mutex);
1706
Eliad Pellerbaf62772011-10-10 10:12:52 +02001707 wl1271_flush_deferred_work(wl);
1708 cancel_delayed_work_sync(&wl->scan_complete_work);
1709 cancel_work_sync(&wl->netstack_work);
1710 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001711 cancel_delayed_work_sync(&wl->elp_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02001712 cancel_delayed_work_sync(&wl->tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03001713 cancel_delayed_work_sync(&wl->connection_loss_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001714
1715 /* let's notify MAC80211 about the remaining pending TX frames */
1716 wl12xx_tx_reset(wl, true);
1717 mutex_lock(&wl->mutex);
1718
1719 wl1271_power_off(wl);
1720
1721 wl->band = IEEE80211_BAND_2GHZ;
1722
1723 wl->rx_counter = 0;
1724 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001725 wl->channel_type = NL80211_CHAN_NO_HT;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001726 wl->tx_blocks_available = 0;
1727 wl->tx_allocated_blocks = 0;
1728 wl->tx_results_count = 0;
1729 wl->tx_packets_count = 0;
1730 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001731 wl->ap_fw_ps_map = 0;
1732 wl->ap_ps_map = 0;
1733 wl->sched_scanning = false;
1734 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1735 memset(wl->links_map, 0, sizeof(wl->links_map));
1736 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1737 wl->active_sta_count = 0;
1738
1739 /* The system link is always allocated */
1740 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1741
1742 /*
1743 * this is performed after the cancel_work calls and the associated
1744 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1745 * get executed before all these vars have been reset.
1746 */
1747 wl->flags = 0;
1748
1749 wl->tx_blocks_freed = 0;
1750
1751 for (i = 0; i < NUM_TX_QUEUES; i++) {
1752 wl->tx_pkts_freed[i] = 0;
1753 wl->tx_allocated_pkts[i] = 0;
1754 }
1755
1756 wl1271_debugfs_reset(wl);
1757
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001758 kfree(wl->fw_status_1);
1759 wl->fw_status_1 = NULL;
1760 wl->fw_status_2 = NULL;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001761 kfree(wl->tx_res_if);
1762 wl->tx_res_if = NULL;
1763 kfree(wl->target_mem_map);
1764 wl->target_mem_map = NULL;
1765
1766 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001767}
1768
Eliad Pellere5a359f2011-10-10 10:13:15 +02001769static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1770{
1771 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1772 WL12XX_MAX_RATE_POLICIES);
1773 if (policy >= WL12XX_MAX_RATE_POLICIES)
1774 return -EBUSY;
1775
1776 __set_bit(policy, wl->rate_policies_map);
1777 *idx = policy;
1778 return 0;
1779}
1780
1781static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1782{
1783 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1784 return;
1785
1786 __clear_bit(*idx, wl->rate_policies_map);
1787 *idx = WL12XX_MAX_RATE_POLICIES;
1788}
1789
Eliad Peller536129c2011-10-05 11:55:45 +02001790static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001791{
Eliad Peller536129c2011-10-05 11:55:45 +02001792 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001793 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001794 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001795 return WL1271_ROLE_P2P_GO;
1796 else
1797 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001798
1799 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001800 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001801 return WL1271_ROLE_P2P_CL;
1802 else
1803 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001804
Eliad Peller227e81e2011-08-14 13:17:26 +03001805 case BSS_TYPE_IBSS:
1806 return WL1271_ROLE_IBSS;
1807
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001808 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001809 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001810 }
1811 return WL12XX_INVALID_ROLE_TYPE;
1812}
1813
Eliad Peller83587502011-10-10 10:12:53 +02001814static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001815{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001816 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001817 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001818
Eliad Peller48e93e42011-10-10 10:12:58 +02001819 /* clear everything but the persistent data */
1820 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001821
1822 switch (ieee80211_vif_type_p2p(vif)) {
1823 case NL80211_IFTYPE_P2P_CLIENT:
1824 wlvif->p2p = 1;
1825 /* fall-through */
1826 case NL80211_IFTYPE_STATION:
1827 wlvif->bss_type = BSS_TYPE_STA_BSS;
1828 break;
1829 case NL80211_IFTYPE_ADHOC:
1830 wlvif->bss_type = BSS_TYPE_IBSS;
1831 break;
1832 case NL80211_IFTYPE_P2P_GO:
1833 wlvif->p2p = 1;
1834 /* fall-through */
1835 case NL80211_IFTYPE_AP:
1836 wlvif->bss_type = BSS_TYPE_AP_BSS;
1837 break;
1838 default:
1839 wlvif->bss_type = MAX_BSS_TYPE;
1840 return -EOPNOTSUPP;
1841 }
1842
Eliad Peller0603d892011-10-05 11:55:51 +02001843 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001844 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001845 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001846
Eliad Pellere936bbe2011-10-05 11:55:56 +02001847 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1848 wlvif->bss_type == BSS_TYPE_IBSS) {
1849 /* init sta/ibss data */
1850 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001851 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1852 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1853 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03001854 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
1855 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
1856 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001857 } else {
1858 /* init ap data */
1859 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1860 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001861 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1862 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1863 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1864 wl12xx_allocate_rate_policy(wl,
1865 &wlvif->ap.ucast_rate_idx[i]);
Luciano Coelho15e05bc2012-05-10 12:14:05 +03001866 wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
1867 /*
1868 * TODO: check if basic_rate shouldn't be
1869 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1870 * instead (the same thing for STA above).
1871 */
1872 wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
1873 /* TODO: this seems to be used only for STA, check it */
1874 wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001875 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001876
Eliad Peller83587502011-10-10 10:12:53 +02001877 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1878 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller6a899792011-10-05 11:55:58 +02001879 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1880
Eliad Peller1b92f152011-10-10 10:13:09 +02001881 /*
1882 * mac80211 configures some values globally, while we treat them
1883 * per-interface. thus, on init, we have to copy them from wl
1884 */
1885 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001886 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001887 wlvif->power_level = wl->power_level;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03001888 wlvif->channel_type = wl->channel_type;
Eliad Peller1b92f152011-10-10 10:13:09 +02001889
Eliad Peller9eb599e2011-10-10 10:12:59 +02001890 INIT_WORK(&wlvif->rx_streaming_enable_work,
1891 wl1271_rx_streaming_enable_work);
1892 INIT_WORK(&wlvif->rx_streaming_disable_work,
1893 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001894 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001895
Eliad Peller9eb599e2011-10-10 10:12:59 +02001896 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1897 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001898 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001899}
1900
Eliad Peller1d095472011-10-10 10:12:49 +02001901static bool wl12xx_init_fw(struct wl1271 *wl)
1902{
1903 int retries = WL1271_BOOT_RETRIES;
1904 bool booted = false;
1905 struct wiphy *wiphy = wl->hw->wiphy;
1906 int ret;
1907
1908 while (retries) {
1909 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001910 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02001911 if (ret < 0)
1912 goto power_off;
1913
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001914 ret = wl->ops->boot(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02001915 if (ret < 0)
1916 goto power_off;
1917
1918 ret = wl1271_hw_init(wl);
1919 if (ret < 0)
1920 goto irq_disable;
1921
1922 booted = true;
1923 break;
1924
1925irq_disable:
1926 mutex_unlock(&wl->mutex);
1927 /* Unlocking the mutex in the middle of handling is
1928 inherently unsafe. In this case we deem it safe to do,
1929 because we need to let any possibly pending IRQ out of
1930 the system (and while we are WL1271_STATE_OFF the IRQ
1931 work function will not do anything.) Also, any other
1932 possible concurrent operations will fail due to the
1933 current state, hence the wl1271 struct should be safe. */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001934 wlcore_disable_interrupts(wl);
Eliad Peller1d095472011-10-10 10:12:49 +02001935 wl1271_flush_deferred_work(wl);
1936 cancel_work_sync(&wl->netstack_work);
1937 mutex_lock(&wl->mutex);
1938power_off:
1939 wl1271_power_off(wl);
1940 }
1941
1942 if (!booted) {
1943 wl1271_error("firmware boot failed despite %d retries",
1944 WL1271_BOOT_RETRIES);
1945 goto out;
1946 }
1947
1948 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
1949
1950 /* update hw/fw version info in wiphy struct */
1951 wiphy->hw_version = wl->chip.id;
1952 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1953 sizeof(wiphy->fw_version));
1954
1955 /*
1956 * Now we know if 11a is supported (info from the NVS), so disable
1957 * 11a channels if not supported
1958 */
1959 if (!wl->enable_11a)
1960 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1961
1962 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1963 wl->enable_11a ? "" : "not ");
1964
1965 wl->state = WL1271_STATE_ON;
1966out:
1967 return booted;
1968}
1969
Eliad Peller92e712d2011-12-18 20:25:43 +02001970static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
1971{
1972 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
1973}
1974
Eliad Peller4549d092012-02-06 13:07:52 +02001975/*
1976 * Check whether a fw switch (i.e. moving from one loaded
1977 * fw to another) is needed. This function is also responsible
1978 * for updating wl->last_vif_count, so it must be called before
1979 * loading a non-plt fw (so the correct fw (single-role/multi-role)
1980 * will be used).
1981 */
1982static bool wl12xx_need_fw_change(struct wl1271 *wl,
1983 struct vif_counter_data vif_counter_data,
1984 bool add)
1985{
1986 enum wl12xx_fw_type current_fw = wl->fw_type;
1987 u8 vif_count = vif_counter_data.counter;
1988
1989 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
1990 return false;
1991
1992 /* increase the vif count if this is a new vif */
1993 if (add && !vif_counter_data.cur_vif_running)
1994 vif_count++;
1995
1996 wl->last_vif_count = vif_count;
1997
1998 /* no need for fw change if the device is OFF */
1999 if (wl->state == WL1271_STATE_OFF)
2000 return false;
2001
2002 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2003 return true;
2004 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2005 return true;
2006
2007 return false;
2008}
2009
Eliad Peller3dee4392012-02-06 12:47:56 +02002010/*
2011 * Enter "forced psm". Make sure the sta is in psm against the ap,
2012 * to make the fw switch a bit more disconnection-persistent.
2013 */
2014static void wl12xx_force_active_psm(struct wl1271 *wl)
2015{
2016 struct wl12xx_vif *wlvif;
2017
2018 wl12xx_for_each_wlvif_sta(wl, wlvif) {
2019 wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
2020 }
2021}
2022
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002023static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2024 struct ieee80211_vif *vif)
2025{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002027 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4549d092012-02-06 13:07:52 +02002028 struct vif_counter_data vif_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002030 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002031 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032
Johannes Bergea086352012-01-19 09:29:58 +01002033 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2034 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002035
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002036 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002037 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038
Eliad Peller4549d092012-02-06 13:07:52 +02002039 wl12xx_get_vif_count(hw, vif, &vif_count);
2040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002042 ret = wl1271_ps_elp_wakeup(wl);
2043 if (ret < 0)
2044 goto out_unlock;
2045
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002046 /*
2047 * in some very corner case HW recovery scenarios its possible to
2048 * get here before __wl1271_op_remove_interface is complete, so
2049 * opt out if that is the case.
2050 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002051 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2052 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002053 ret = -EBUSY;
2054 goto out;
2055 }
2056
Eliad Peller3fcdab72012-02-06 12:47:54 +02002057
Eliad Peller83587502011-10-10 10:12:53 +02002058 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002059 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002060 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061
Eliad Peller252efa42011-10-05 11:56:00 +02002062 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002063 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002064 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2065 ret = -EINVAL;
2066 goto out;
2067 }
Eliad Peller1d095472011-10-10 10:12:49 +02002068
Eliad Peller4549d092012-02-06 13:07:52 +02002069 if (wl12xx_need_fw_change(wl, vif_count, true)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002070 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002071 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002072 mutex_unlock(&wl->mutex);
2073 wl1271_recovery_work(&wl->recovery_work);
2074 return 0;
2075 }
2076
Eliad Peller784f6942011-10-05 11:55:39 +02002077 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002078 * TODO: after the nvs issue will be solved, move this block
2079 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002080 */
Eliad Peller1d095472011-10-10 10:12:49 +02002081 if (wl->state == WL1271_STATE_OFF) {
2082 /*
2083 * we still need this in order to configure the fw
2084 * while uploading the nvs
2085 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002086 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087
Eliad Peller1d095472011-10-10 10:12:49 +02002088 booted = wl12xx_init_fw(wl);
2089 if (!booted) {
2090 ret = -EINVAL;
2091 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002092 }
Eliad Peller1d095472011-10-10 10:12:49 +02002093 }
Eliad Peller04e80792011-08-14 13:17:09 +03002094
Eliad Peller1d095472011-10-10 10:12:49 +02002095 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2096 wlvif->bss_type == BSS_TYPE_IBSS) {
2097 /*
2098 * The device role is a special role used for
2099 * rx and tx frames prior to association (as
2100 * the STA role can get packets only from
2101 * its associated bssid)
2102 */
Eliad Peller784f6942011-10-05 11:55:39 +02002103 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002104 WL1271_ROLE_DEVICE,
2105 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002106 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002107 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002108 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002109
Eliad Peller1d095472011-10-10 10:12:49 +02002110 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2111 role_type, &wlvif->role_id);
2112 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002113 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002114
2115 ret = wl1271_init_vif_specific(wl, vif);
2116 if (ret < 0)
2117 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002118
Eliad Peller87627212011-10-10 10:12:54 +02002119 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002120 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002121
2122 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2123 wl->ap_count++;
2124 else
2125 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002126out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002127 wl1271_ps_elp_sleep(wl);
2128out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002129 mutex_unlock(&wl->mutex);
2130
2131 return ret;
2132}
2133
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002134static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002135 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002136 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137{
Eliad Peller536129c2011-10-05 11:55:45 +02002138 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002139 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002141 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142
Eliad Peller10c8cd02011-10-10 10:13:06 +02002143 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2144 return;
2145
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002146 /* because of hardware recovery, we may get here twice */
2147 if (wl->state != WL1271_STATE_ON)
2148 return;
2149
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002150 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151
Eliad Pellerbaf62772011-10-10 10:12:52 +02002152 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2153 wl->scan_vif == vif) {
Arik Nemtsov55df5af2012-03-03 22:18:00 +02002154 /*
2155 * Rearm the tx watchdog just before idling scan. This
2156 * prevents just-finished scans from triggering the watchdog
2157 */
2158 wl12xx_rearm_tx_watchdog_locked(wl);
2159
Luciano Coelho08688d62010-07-08 17:50:07 +03002160 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002161 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002162 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002163 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002164 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 }
2166
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002167 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2168 /* disable active roles */
2169 ret = wl1271_ps_elp_wakeup(wl);
2170 if (ret < 0)
2171 goto deinit;
2172
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002173 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2174 wlvif->bss_type == BSS_TYPE_IBSS) {
2175 if (wl12xx_dev_role_started(wlvif))
2176 wl12xx_stop_dev(wl, wlvif);
2177
Eliad Peller7edebf52011-10-05 11:55:52 +02002178 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002179 if (ret < 0)
2180 goto deinit;
2181 }
2182
Eliad Peller0603d892011-10-05 11:55:51 +02002183 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002184 if (ret < 0)
2185 goto deinit;
2186
2187 wl1271_ps_elp_sleep(wl);
2188 }
2189deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002190 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002191 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002192
2193 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2194 wlvif->bss_type == BSS_TYPE_IBSS) {
2195 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2196 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2197 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2198 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2199 } else {
2200 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2201 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2202 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2203 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2204 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2205 wl12xx_free_rate_policy(wl,
2206 &wlvif->ap.ucast_rate_idx[i]);
Eliad Peller830be7e2012-03-19 11:32:55 +02002207 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002208 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002209
Eyal Shapira3eba4a02012-03-19 12:06:27 +02002210 dev_kfree_skb(wlvif->probereq);
2211 wlvif->probereq = NULL;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002212 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002213 if (wl->last_wlvif == wlvif)
2214 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002215 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002216 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002217 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002218 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002219
Eliad Pellera4e41302011-10-11 11:49:15 +02002220 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2221 wl->ap_count--;
2222 else
2223 wl->sta_count--;
2224
Eliad Pellerbaf62772011-10-10 10:12:52 +02002225 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002226
Eliad Peller9eb599e2011-10-10 10:12:59 +02002227 del_timer_sync(&wlvif->rx_streaming_timer);
2228 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2229 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002230
Eliad Pellerbaf62772011-10-10 10:12:52 +02002231 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002232}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002233
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002234static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2235 struct ieee80211_vif *vif)
2236{
2237 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002238 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002239 struct wl12xx_vif *iter;
Eliad Peller4549d092012-02-06 13:07:52 +02002240 struct vif_counter_data vif_count;
2241 bool cancel_recovery = true;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002242
Eliad Peller4549d092012-02-06 13:07:52 +02002243 wl12xx_get_vif_count(hw, vif, &vif_count);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002244 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002245
2246 if (wl->state == WL1271_STATE_OFF ||
2247 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2248 goto out;
2249
Juuso Oikarinen67353292010-11-18 15:19:02 +02002250 /*
2251 * wl->vif can be null here if someone shuts down the interface
2252 * just when hardware recovery has been started.
2253 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002254 wl12xx_for_each_wlvif(wl, iter) {
2255 if (iter != wlvif)
2256 continue;
2257
Eliad Peller536129c2011-10-05 11:55:45 +02002258 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002259 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002260 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002261 WARN_ON(iter != wlvif);
Eliad Peller4549d092012-02-06 13:07:52 +02002262 if (wl12xx_need_fw_change(wl, vif_count, false)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002263 wl12xx_force_active_psm(wl);
Eliad Pellere9ba7152012-03-04 10:55:54 +02002264 set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
Eliad Peller4549d092012-02-06 13:07:52 +02002265 wl12xx_queue_recovery_work(wl);
2266 cancel_recovery = false;
2267 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002268out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002269 mutex_unlock(&wl->mutex);
Eliad Peller4549d092012-02-06 13:07:52 +02002270 if (cancel_recovery)
2271 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002272}
2273
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002274static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2275 struct ieee80211_vif *vif,
2276 enum nl80211_iftype new_type, bool p2p)
2277{
Eliad Peller4549d092012-02-06 13:07:52 +02002278 struct wl1271 *wl = hw->priv;
2279 int ret;
2280
2281 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002282 wl1271_op_remove_interface(hw, vif);
2283
Eliad Peller249e9692012-03-04 10:55:50 +02002284 vif->type = new_type;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002285 vif->p2p = p2p;
Eliad Peller4549d092012-02-06 13:07:52 +02002286 ret = wl1271_op_add_interface(hw, vif);
2287
2288 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2289 return ret;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002290}
2291
Eliad Peller87fbcb02011-10-05 11:55:41 +02002292static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2293 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002294{
2295 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002296 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002297
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002298 /*
2299 * One of the side effects of the JOIN command is that is clears
2300 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2301 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002302 * Currently the only valid scenario for JOIN during association
2303 * is on roaming, in which case we will also be given new keys.
2304 * Keep the below message for now, unless it starts bothering
2305 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002306 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002307 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002308 wl1271_info("JOIN while associated.");
2309
Eliad Peller5ec8a442012-02-02 12:22:09 +02002310 /* clear encryption type */
2311 wlvif->encryption_type = KEY_NONE;
2312
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002313 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002314 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002315
Eliad Peller227e81e2011-08-14 13:17:26 +03002316 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002317 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002318 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002319 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002320 if (ret < 0)
2321 goto out;
2322
Eliad Pellerba8447f2011-10-10 10:13:00 +02002323 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002324 goto out;
2325
2326 /*
2327 * The join command disable the keep-alive mode, shut down its process,
2328 * and also clear the template config, so we need to reset it all after
2329 * the join. The acx_aid starts the keep-alive process, and the order
2330 * of the commands below is relevant.
2331 */
Eliad Peller0603d892011-10-05 11:55:51 +02002332 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002333 if (ret < 0)
2334 goto out;
2335
Eliad Peller0603d892011-10-05 11:55:51 +02002336 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002337 if (ret < 0)
2338 goto out;
2339
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002340 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002341 if (ret < 0)
2342 goto out;
2343
Eliad Peller0603d892011-10-05 11:55:51 +02002344 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2345 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002346 ACX_KEEP_ALIVE_TPL_VALID);
2347 if (ret < 0)
2348 goto out;
2349
2350out:
2351 return ret;
2352}
2353
Eliad Peller0603d892011-10-05 11:55:51 +02002354static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002355{
2356 int ret;
2357
Eliad Peller52630c52011-10-10 10:13:08 +02002358 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002359 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2360
Shahar Levi6d158ff2011-09-08 13:01:33 +03002361 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002362 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002363 }
2364
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002365 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002366 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002367 if (ret < 0)
2368 goto out;
2369
Oz Krakowskib992c682011-06-26 10:36:02 +03002370 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002371 wlvif->tx_security_last_seq_lsb = 0;
2372 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002373
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002374out:
2375 return ret;
2376}
2377
Eliad Peller87fbcb02011-10-05 11:55:41 +02002378static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002379{
Eliad Peller1b92f152011-10-10 10:13:09 +02002380 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002381 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002382}
2383
Eliad Peller87fbcb02011-10-05 11:55:41 +02002384static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2385 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002386{
2387 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002388 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2389
2390 if (idle == cur_idle)
2391 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002392
2393 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002394 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002395 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002396 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002397 if (ret < 0)
2398 goto out;
2399 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002400 wlvif->rate_set =
2401 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2402 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002403 if (ret < 0)
2404 goto out;
2405 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002406 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002407 ACX_KEEP_ALIVE_TPL_INVALID);
2408 if (ret < 0)
2409 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002410 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002411 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002412 /* The current firmware only supports sched_scan in idle */
2413 if (wl->sched_scanning) {
2414 wl1271_scan_sched_scan_stop(wl);
2415 ieee80211_sched_scan_stopped(wl->hw);
2416 }
2417
Eliad Peller679a6732011-10-11 11:55:44 +02002418 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002419 if (ret < 0)
2420 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002421 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002422 }
2423
2424out:
2425 return ret;
2426}
2427
Eliad Peller9f259c42011-10-10 10:13:12 +02002428static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2429 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430{
Eliad Peller9f259c42011-10-10 10:13:12 +02002431 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2432 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433
2434 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2435
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002436 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002437 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002438 ((wlvif->band != conf->channel->band) ||
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002439 (wlvif->channel != channel) ||
2440 (wlvif->channel_type != conf->channel_type))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002441 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002442 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002443 wlvif->band = conf->channel->band;
2444 wlvif->channel = channel;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002445 wlvif->channel_type = conf->channel_type;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002446
Arik Nemtsovebc7e572012-05-10 12:13:34 +03002447 if (is_ap) {
2448 ret = wl1271_init_ap_rates(wl, wlvif);
2449 if (ret < 0)
2450 wl1271_error("AP rate policy change failed %d",
2451 ret);
2452 } else {
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002453 /*
2454 * FIXME: the mac80211 should really provide a fixed
2455 * rate to use here. for now, just use the smallest
2456 * possible rate for the band as a fixed rate for
2457 * association frames and other control messages.
2458 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002459 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002460 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002461
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002462 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002463 wl1271_tx_min_rate_get(wl,
2464 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002465 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002466 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002467 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002468 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002469
Eliad Peller121af042012-03-04 10:55:51 +02002470 /*
2471 * change the ROC channel. do it only if we are
2472 * not idle. otherwise, CROC will be called
2473 * anyway.
2474 */
2475 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2476 &wlvif->flags) &&
2477 wl12xx_dev_role_started(wlvif) &&
2478 !(conf->flags & IEEE80211_CONF_IDLE)) {
2479 ret = wl12xx_stop_dev(wl, wlvif);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002480 if (ret < 0)
Eliad Peller121af042012-03-04 10:55:51 +02002481 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002482
Eliad Peller121af042012-03-04 10:55:51 +02002483 ret = wl12xx_start_dev(wl, wlvif);
2484 if (ret < 0)
2485 return ret;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002486 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002487 }
2488 }
2489
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002490 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002492 if ((conf->flags & IEEE80211_CONF_PS) &&
2493 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002494 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002495
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002496 int ps_mode;
2497 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002498
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002499 if (wl->conf.conn.forced_ps) {
2500 ps_mode = STATION_POWER_SAVE_MODE;
2501 ps_mode_str = "forced";
2502 } else {
2503 ps_mode = STATION_AUTO_PS_MODE;
2504 ps_mode_str = "auto";
2505 }
2506
2507 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2508
2509 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2510
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002511 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002512 wl1271_warning("enter %s ps failed %d",
2513 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002514
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002515 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002516 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002518 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2519
Eliad Peller0603d892011-10-05 11:55:51 +02002520 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002521 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002522 if (ret < 0)
2523 wl1271_warning("exit auto ps failed %d", ret);
2524 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 }
2526
Eliad Peller6bd65022011-10-10 10:13:11 +02002527 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002528 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002529 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002530 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
Eliad Peller6bd65022011-10-10 10:13:11 +02002532 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 }
2534
Eliad Peller9f259c42011-10-10 10:13:12 +02002535 return 0;
2536}
2537
2538static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2539{
2540 struct wl1271 *wl = hw->priv;
2541 struct wl12xx_vif *wlvif;
2542 struct ieee80211_conf *conf = &hw->conf;
2543 int channel, ret = 0;
2544
2545 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2546
2547 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2548 " changed 0x%x",
2549 channel,
2550 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2551 conf->power_level,
2552 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2553 changed);
2554
2555 /*
2556 * mac80211 will go to idle nearly immediately after transmitting some
2557 * frames, such as the deauth. To make sure those frames reach the air,
2558 * wait here until the TX queue is fully flushed.
2559 */
2560 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2561 (conf->flags & IEEE80211_CONF_IDLE))
2562 wl1271_tx_flush(wl);
2563
2564 mutex_lock(&wl->mutex);
2565
2566 /* we support configuring the channel and band even while off */
2567 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2568 wl->band = conf->channel->band;
2569 wl->channel = channel;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03002570 wl->channel_type = conf->channel_type;
Eliad Peller9f259c42011-10-10 10:13:12 +02002571 }
2572
2573 if (changed & IEEE80211_CONF_CHANGE_POWER)
2574 wl->power_level = conf->power_level;
2575
2576 if (unlikely(wl->state == WL1271_STATE_OFF))
2577 goto out;
2578
2579 ret = wl1271_ps_elp_wakeup(wl);
2580 if (ret < 0)
2581 goto out;
2582
2583 /* configure each interface */
2584 wl12xx_for_each_wlvif(wl, wlvif) {
2585 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2586 if (ret < 0)
2587 goto out_sleep;
2588 }
2589
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590out_sleep:
2591 wl1271_ps_elp_sleep(wl);
2592
2593out:
2594 mutex_unlock(&wl->mutex);
2595
2596 return ret;
2597}
2598
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002599struct wl1271_filter_params {
2600 bool enabled;
2601 int mc_list_length;
2602 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2603};
2604
Jiri Pirko22bedad32010-04-01 21:22:57 +00002605static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2606 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002607{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002608 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002609 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002610 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002611
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002612 if (unlikely(wl->state == WL1271_STATE_OFF))
2613 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002614
Juuso Oikarinen74441132009-10-13 12:47:53 +03002615 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002616 if (!fp) {
2617 wl1271_error("Out of memory setting filters.");
2618 return 0;
2619 }
2620
2621 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002622 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002623 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2624 fp->enabled = false;
2625 } else {
2626 fp->enabled = true;
2627 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002628 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002629 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002630 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002631 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002632 }
2633
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002634 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002635}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002636
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002637#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2638 FIF_ALLMULTI | \
2639 FIF_FCSFAIL | \
2640 FIF_BCN_PRBRESP_PROMISC | \
2641 FIF_CONTROL | \
2642 FIF_OTHER_BSS)
2643
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002644static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2645 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002646 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002648 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002649 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002650 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002651
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002652 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002653
Arik Nemtsov7d057862010-10-16 19:25:35 +02002654 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2655 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002656
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002657 mutex_lock(&wl->mutex);
2658
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002659 *total &= WL1271_SUPPORTED_FILTERS;
2660 changed &= WL1271_SUPPORTED_FILTERS;
2661
2662 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002663 goto out;
2664
Ido Yariva6208652011-03-01 15:14:41 +02002665 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002666 if (ret < 0)
2667 goto out;
2668
Eliad Peller6e8cd332011-10-10 10:13:13 +02002669 wl12xx_for_each_wlvif(wl, wlvif) {
2670 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2671 if (*total & FIF_ALLMULTI)
2672 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2673 false,
2674 NULL, 0);
2675 else if (fp)
2676 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2677 fp->enabled,
2678 fp->mc_list,
2679 fp->mc_list_length);
2680 if (ret < 0)
2681 goto out_sleep;
2682 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002683 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002685 /*
2686 * the fw doesn't provide an api to configure the filters. instead,
2687 * the filters configuration is based on the active roles / ROC
2688 * state.
2689 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002690
2691out_sleep:
2692 wl1271_ps_elp_sleep(wl);
2693
2694out:
2695 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002696 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697}
2698
Eliad Peller170d0e62011-10-05 11:56:06 +02002699static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2700 u8 id, u8 key_type, u8 key_size,
2701 const u8 *key, u8 hlid, u32 tx_seq_32,
2702 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002703{
2704 struct wl1271_ap_key *ap_key;
2705 int i;
2706
2707 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2708
2709 if (key_size > MAX_KEY_SIZE)
2710 return -EINVAL;
2711
2712 /*
2713 * Find next free entry in ap_keys. Also check we are not replacing
2714 * an existing key.
2715 */
2716 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002717 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002718 break;
2719
Eliad Peller170d0e62011-10-05 11:56:06 +02002720 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002721 wl1271_warning("trying to record key replacement");
2722 return -EINVAL;
2723 }
2724 }
2725
2726 if (i == MAX_NUM_KEYS)
2727 return -EBUSY;
2728
2729 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2730 if (!ap_key)
2731 return -ENOMEM;
2732
2733 ap_key->id = id;
2734 ap_key->key_type = key_type;
2735 ap_key->key_size = key_size;
2736 memcpy(ap_key->key, key, key_size);
2737 ap_key->hlid = hlid;
2738 ap_key->tx_seq_32 = tx_seq_32;
2739 ap_key->tx_seq_16 = tx_seq_16;
2740
Eliad Peller170d0e62011-10-05 11:56:06 +02002741 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002742 return 0;
2743}
2744
Eliad Peller170d0e62011-10-05 11:56:06 +02002745static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002746{
2747 int i;
2748
2749 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002750 kfree(wlvif->ap.recorded_keys[i]);
2751 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002752 }
2753}
2754
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002755static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756{
2757 int i, ret = 0;
2758 struct wl1271_ap_key *key;
2759 bool wep_key_added = false;
2760
2761 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002762 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002763 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002764 break;
2765
Eliad Peller170d0e62011-10-05 11:56:06 +02002766 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002767 hlid = key->hlid;
2768 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002769 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002770
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002771 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002772 key->id, key->key_type,
2773 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002774 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002775 key->tx_seq_16);
2776 if (ret < 0)
2777 goto out;
2778
2779 if (key->key_type == KEY_WEP)
2780 wep_key_added = true;
2781 }
2782
2783 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002784 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002785 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002786 if (ret < 0)
2787 goto out;
2788 }
2789
2790out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002791 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792 return ret;
2793}
2794
Eliad Peller536129c2011-10-05 11:55:45 +02002795static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2796 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 u8 key_size, const u8 *key, u32 tx_seq_32,
2798 u16 tx_seq_16, struct ieee80211_sta *sta)
2799{
2800 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002801 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802
Arik Nemtsov3edab302011-12-07 23:38:47 +02002803 /*
2804 * A role set to GEM cipher requires different Tx settings (namely
2805 * spare blocks). Note when we are in this mode so the HW can adjust.
2806 */
2807 if (key_type == KEY_GEM) {
2808 if (action == KEY_ADD_OR_REPLACE)
2809 wlvif->is_gem = true;
2810 else if (action == KEY_REMOVE)
2811 wlvif->is_gem = false;
2812 }
2813
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 if (is_ap) {
2815 struct wl1271_station *wl_sta;
2816 u8 hlid;
2817
2818 if (sta) {
2819 wl_sta = (struct wl1271_station *)sta->drv_priv;
2820 hlid = wl_sta->hlid;
2821 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002822 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002823 }
2824
Eliad Peller53d40d02011-10-10 10:13:02 +02002825 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002826 /*
2827 * We do not support removing keys after AP shutdown.
2828 * Pretend we do to make mac80211 happy.
2829 */
2830 if (action != KEY_ADD_OR_REPLACE)
2831 return 0;
2832
Eliad Peller170d0e62011-10-05 11:56:06 +02002833 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 key_type, key_size,
2835 key, hlid, tx_seq_32,
2836 tx_seq_16);
2837 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002838 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002839 id, key_type, key_size,
2840 key, hlid, tx_seq_32,
2841 tx_seq_16);
2842 }
2843
2844 if (ret < 0)
2845 return ret;
2846 } else {
2847 const u8 *addr;
2848 static const u8 bcast_addr[ETH_ALEN] = {
2849 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2850 };
2851
2852 addr = sta ? sta->addr : bcast_addr;
2853
2854 if (is_zero_ether_addr(addr)) {
2855 /* We dont support TX only encryption */
2856 return -EOPNOTSUPP;
2857 }
2858
2859 /* The wl1271 does not allow to remove unicast keys - they
2860 will be cleared automatically on next CMD_JOIN. Ignore the
2861 request silently, as we dont want the mac80211 to emit
2862 an error message. */
2863 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2864 return 0;
2865
Eliad Peller010d3d32011-08-14 13:17:31 +03002866 /* don't remove key if hlid was already deleted */
2867 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002868 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002869 return 0;
2870
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002871 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002872 id, key_type, key_size,
2873 key, addr, tx_seq_32,
2874 tx_seq_16);
2875 if (ret < 0)
2876 return ret;
2877
2878 /* the default WEP key needs to be configured at least once */
2879 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002880 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002881 wlvif->default_key,
2882 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002883 if (ret < 0)
2884 return ret;
2885 }
2886 }
2887
2888 return 0;
2889}
2890
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2892 struct ieee80211_vif *vif,
2893 struct ieee80211_sta *sta,
2894 struct ieee80211_key_conf *key_conf)
2895{
2896 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002897 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002899 u32 tx_seq_32 = 0;
2900 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002901 u8 key_type;
2902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2904
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002907 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002908 key_conf->keylen, key_conf->flags);
2909 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002911 mutex_lock(&wl->mutex);
2912
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002913 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2914 ret = -EAGAIN;
2915 goto out_unlock;
2916 }
2917
Ido Yariva6208652011-03-01 15:14:41 +02002918 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002919 if (ret < 0)
2920 goto out_unlock;
2921
Johannes Berg97359d12010-08-10 09:46:38 +02002922 switch (key_conf->cipher) {
2923 case WLAN_CIPHER_SUITE_WEP40:
2924 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 key_type = KEY_WEP;
2926
2927 key_conf->hw_key_idx = key_conf->keyidx;
2928 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002929 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 key_type = KEY_TKIP;
2931
2932 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002933 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2934 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002935 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002936 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937 key_type = KEY_AES;
2938
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002939 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002940 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2941 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002943 case WL1271_CIPHER_SUITE_GEM:
2944 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002945 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2946 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002947 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002949 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950
2951 ret = -EOPNOTSUPP;
2952 goto out_sleep;
2953 }
2954
2955 switch (cmd) {
2956 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002957 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002958 key_conf->keyidx, key_type,
2959 key_conf->keylen, key_conf->key,
2960 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 if (ret < 0) {
2962 wl1271_error("Could not add or replace key");
2963 goto out_sleep;
2964 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02002965
2966 /*
2967 * reconfiguring arp response if the unicast (or common)
2968 * encryption key type was changed
2969 */
2970 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
2971 (sta || key_type == KEY_WEP) &&
2972 wlvif->encryption_type != key_type) {
2973 wlvif->encryption_type = key_type;
2974 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
2975 if (ret < 0) {
2976 wl1271_warning("build arp rsp failed: %d", ret);
2977 goto out_sleep;
2978 }
2979 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 break;
2981
2982 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002983 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002984 key_conf->keyidx, key_type,
2985 key_conf->keylen, key_conf->key,
2986 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 if (ret < 0) {
2988 wl1271_error("Could not remove key");
2989 goto out_sleep;
2990 }
2991 break;
2992
2993 default:
2994 wl1271_error("Unsupported key cmd 0x%x", cmd);
2995 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 break;
2997 }
2998
2999out_sleep:
3000 wl1271_ps_elp_sleep(wl);
3001
3002out_unlock:
3003 mutex_unlock(&wl->mutex);
3004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005 return ret;
3006}
3007
3008static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003009 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010 struct cfg80211_scan_request *req)
3011{
3012 struct wl1271 *wl = hw->priv;
3013 int ret;
3014 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003015 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016
3017 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3018
3019 if (req->n_ssids) {
3020 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003021 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 }
3023
3024 mutex_lock(&wl->mutex);
3025
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003026 if (wl->state == WL1271_STATE_OFF) {
3027 /*
3028 * We cannot return -EBUSY here because cfg80211 will expect
3029 * a call to ieee80211_scan_completed if we do - in this case
3030 * there won't be any call.
3031 */
3032 ret = -EAGAIN;
3033 goto out;
3034 }
3035
Ido Yariva6208652011-03-01 15:14:41 +02003036 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037 if (ret < 0)
3038 goto out;
3039
Eliad Peller97fd3112012-03-04 10:55:52 +02003040 /* fail if there is any role in ROC */
3041 if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
Eliad Peller92e712d2011-12-18 20:25:43 +02003042 /* don't allow scanning right now */
3043 ret = -EBUSY;
3044 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003045 }
3046
Eliad Peller784f6942011-10-05 11:55:39 +02003047 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003048out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050out:
3051 mutex_unlock(&wl->mutex);
3052
3053 return ret;
3054}
3055
Eliad Peller73ecce32011-06-27 13:06:45 +03003056static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3057 struct ieee80211_vif *vif)
3058{
3059 struct wl1271 *wl = hw->priv;
3060 int ret;
3061
3062 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3063
3064 mutex_lock(&wl->mutex);
3065
3066 if (wl->state == WL1271_STATE_OFF)
3067 goto out;
3068
3069 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3070 goto out;
3071
3072 ret = wl1271_ps_elp_wakeup(wl);
3073 if (ret < 0)
3074 goto out;
3075
3076 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3077 ret = wl1271_scan_stop(wl);
3078 if (ret < 0)
3079 goto out_sleep;
3080 }
Arik Nemtsov55df5af2012-03-03 22:18:00 +02003081
3082 /*
3083 * Rearm the tx watchdog just before idling scan. This
3084 * prevents just-finished scans from triggering the watchdog
3085 */
3086 wl12xx_rearm_tx_watchdog_locked(wl);
3087
Eliad Peller73ecce32011-06-27 13:06:45 +03003088 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3089 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003090 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003091 wl->scan.req = NULL;
3092 ieee80211_scan_completed(wl->hw, true);
3093
3094out_sleep:
3095 wl1271_ps_elp_sleep(wl);
3096out:
3097 mutex_unlock(&wl->mutex);
3098
3099 cancel_delayed_work_sync(&wl->scan_complete_work);
3100}
3101
Luciano Coelho33c2c062011-05-10 14:46:02 +03003102static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3103 struct ieee80211_vif *vif,
3104 struct cfg80211_sched_scan_request *req,
3105 struct ieee80211_sched_scan_ies *ies)
3106{
3107 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003108 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003109 int ret;
3110
3111 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3112
3113 mutex_lock(&wl->mutex);
3114
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003115 if (wl->state == WL1271_STATE_OFF) {
3116 ret = -EAGAIN;
3117 goto out;
3118 }
3119
Luciano Coelho33c2c062011-05-10 14:46:02 +03003120 ret = wl1271_ps_elp_wakeup(wl);
3121 if (ret < 0)
3122 goto out;
3123
Eliad Peller536129c2011-10-05 11:55:45 +02003124 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003125 if (ret < 0)
3126 goto out_sleep;
3127
Eliad Peller536129c2011-10-05 11:55:45 +02003128 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003129 if (ret < 0)
3130 goto out_sleep;
3131
3132 wl->sched_scanning = true;
3133
3134out_sleep:
3135 wl1271_ps_elp_sleep(wl);
3136out:
3137 mutex_unlock(&wl->mutex);
3138 return ret;
3139}
3140
3141static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3142 struct ieee80211_vif *vif)
3143{
3144 struct wl1271 *wl = hw->priv;
3145 int ret;
3146
3147 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3148
3149 mutex_lock(&wl->mutex);
3150
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003151 if (wl->state == WL1271_STATE_OFF)
3152 goto out;
3153
Luciano Coelho33c2c062011-05-10 14:46:02 +03003154 ret = wl1271_ps_elp_wakeup(wl);
3155 if (ret < 0)
3156 goto out;
3157
3158 wl1271_scan_sched_scan_stop(wl);
3159
3160 wl1271_ps_elp_sleep(wl);
3161out:
3162 mutex_unlock(&wl->mutex);
3163}
3164
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003165static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3166{
3167 struct wl1271 *wl = hw->priv;
3168 int ret = 0;
3169
3170 mutex_lock(&wl->mutex);
3171
3172 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3173 ret = -EAGAIN;
3174 goto out;
3175 }
3176
Ido Yariva6208652011-03-01 15:14:41 +02003177 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003178 if (ret < 0)
3179 goto out;
3180
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003181 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003182 if (ret < 0)
3183 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3184
3185 wl1271_ps_elp_sleep(wl);
3186
3187out:
3188 mutex_unlock(&wl->mutex);
3189
3190 return ret;
3191}
3192
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003193static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3194{
3195 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003196 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003197 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198
3199 mutex_lock(&wl->mutex);
3200
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003201 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3202 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003203 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003204 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003205
Ido Yariva6208652011-03-01 15:14:41 +02003206 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003207 if (ret < 0)
3208 goto out;
3209
Eliad Peller6e8cd332011-10-10 10:13:13 +02003210 wl12xx_for_each_wlvif(wl, wlvif) {
3211 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3212 if (ret < 0)
3213 wl1271_warning("set rts threshold failed: %d", ret);
3214 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003215 wl1271_ps_elp_sleep(wl);
3216
3217out:
3218 mutex_unlock(&wl->mutex);
3219
3220 return ret;
3221}
3222
Eliad Peller1fe9f162011-10-05 11:55:48 +02003223static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003224 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003225{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003226 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003227 u8 ssid_len;
3228 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3229 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003230
Eliad Peller889cb362011-05-01 09:56:45 +03003231 if (!ptr) {
3232 wl1271_error("No SSID in IEs!");
3233 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003234 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003235
Eliad Peller889cb362011-05-01 09:56:45 +03003236 ssid_len = ptr[1];
3237 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3238 wl1271_error("SSID is too long!");
3239 return -EINVAL;
3240 }
3241
Eliad Peller1fe9f162011-10-05 11:55:48 +02003242 wlvif->ssid_len = ssid_len;
3243 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003244 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003245}
3246
Eliad Pellerd48055d2011-09-15 12:07:04 +03003247static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3248{
3249 int len;
3250 const u8 *next, *end = skb->data + skb->len;
3251 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3252 skb->len - ieoffset);
3253 if (!ie)
3254 return;
3255 len = ie[1] + 2;
3256 next = ie + len;
3257 memmove(ie, next, end - next);
3258 skb_trim(skb, skb->len - len);
3259}
3260
Eliad Peller26b4bf22011-09-15 12:07:05 +03003261static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3262 unsigned int oui, u8 oui_type,
3263 int ieoffset)
3264{
3265 int len;
3266 const u8 *next, *end = skb->data + skb->len;
3267 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3268 skb->data + ieoffset,
3269 skb->len - ieoffset);
3270 if (!ie)
3271 return;
3272 len = ie[1] + 2;
3273 next = ie + len;
3274 memmove(ie, next, end - next);
3275 skb_trim(skb, skb->len - len);
3276}
3277
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003278static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3279 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003280{
Eliad Pellercdaac622012-01-31 11:57:16 +02003281 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003282 struct sk_buff *skb;
3283 int ret;
3284
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003285 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003286 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003287 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003288
Eliad Pellercdaac622012-01-31 11:57:16 +02003289 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003290 CMD_TEMPL_AP_PROBE_RESPONSE,
3291 skb->data,
3292 skb->len, 0,
3293 rates);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003294 dev_kfree_skb(skb);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003295
3296 if (ret < 0)
3297 goto out;
3298
3299 wl1271_debug(DEBUG_AP, "probe response updated");
3300 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3301
3302out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003303 return ret;
3304}
3305
3306static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3307 struct ieee80211_vif *vif,
3308 u8 *probe_rsp_data,
3309 size_t probe_rsp_len,
3310 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003311{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003312 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3313 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003314 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3315 int ssid_ie_offset, ie_offset, templ_len;
3316 const u8 *ptr;
3317
3318 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003319 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003320 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003321 CMD_TEMPL_AP_PROBE_RESPONSE,
3322 probe_rsp_data,
3323 probe_rsp_len, 0,
3324 rates);
3325
3326 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3327 wl1271_error("probe_rsp template too big");
3328 return -EINVAL;
3329 }
3330
3331 /* start searching from IE offset */
3332 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3333
3334 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3335 probe_rsp_len - ie_offset);
3336 if (!ptr) {
3337 wl1271_error("No SSID in beacon!");
3338 return -EINVAL;
3339 }
3340
3341 ssid_ie_offset = ptr - probe_rsp_data;
3342 ptr += (ptr[1] + 2);
3343
3344 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3345
3346 /* insert SSID from bss_conf */
3347 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3348 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3349 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3350 bss_conf->ssid, bss_conf->ssid_len);
3351 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3352
3353 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3354 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3355 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3356
Eliad Pellercdaac622012-01-31 11:57:16 +02003357 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003358 CMD_TEMPL_AP_PROBE_RESPONSE,
3359 probe_rsp_templ,
3360 templ_len, 0,
3361 rates);
3362}
3363
Arik Nemtsove78a2872010-10-16 19:07:21 +02003364static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003365 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 struct ieee80211_bss_conf *bss_conf,
3367 u32 changed)
3368{
Eliad Peller0603d892011-10-05 11:55:51 +02003369 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 int ret = 0;
3371
3372 if (changed & BSS_CHANGED_ERP_SLOT) {
3373 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003374 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 else
Eliad Peller0603d892011-10-05 11:55:51 +02003376 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 if (ret < 0) {
3378 wl1271_warning("Set slot time failed %d", ret);
3379 goto out;
3380 }
3381 }
3382
3383 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3384 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003385 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 else
Eliad Peller0603d892011-10-05 11:55:51 +02003387 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 }
3389
3390 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3391 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003392 ret = wl1271_acx_cts_protect(wl, wlvif,
3393 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 else
Eliad Peller0603d892011-10-05 11:55:51 +02003395 ret = wl1271_acx_cts_protect(wl, wlvif,
3396 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 if (ret < 0) {
3398 wl1271_warning("Set ctsprotect failed %d", ret);
3399 goto out;
3400 }
3401 }
3402
3403out:
3404 return ret;
3405}
3406
Luciano Coelho62c2e572012-05-10 12:14:04 +03003407static int wlcore_set_beacon_template(struct wl1271 *wl,
3408 struct ieee80211_vif *vif,
3409 bool is_ap)
3410{
3411 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3412 struct ieee80211_hdr *hdr;
3413 u32 min_rate;
3414 int ret;
3415 int ieoffset = offsetof(struct ieee80211_mgmt,
3416 u.beacon.variable);
3417 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3418 u16 tmpl_id;
3419
3420 if (!beacon) {
3421 ret = -EINVAL;
3422 goto out;
3423 }
3424
3425 wl1271_debug(DEBUG_MASTER, "beacon updated");
3426
3427 ret = wl1271_ssid_set(vif, beacon, ieoffset);
3428 if (ret < 0) {
3429 dev_kfree_skb(beacon);
3430 goto out;
3431 }
3432 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
3433 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3434 CMD_TEMPL_BEACON;
3435 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
3436 beacon->data,
3437 beacon->len, 0,
3438 min_rate);
3439 if (ret < 0) {
3440 dev_kfree_skb(beacon);
3441 goto out;
3442 }
3443
3444 /*
3445 * In case we already have a probe-resp beacon set explicitly
3446 * by usermode, don't use the beacon data.
3447 */
3448 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3449 goto end_bcn;
3450
3451 /* remove TIM ie from probe response */
3452 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3453
3454 /*
3455 * remove p2p ie from probe response.
3456 * the fw reponds to probe requests that don't include
3457 * the p2p ie. probe requests with p2p ie will be passed,
3458 * and will be responded by the supplicant (the spec
3459 * forbids including the p2p ie when responding to probe
3460 * requests that didn't include it).
3461 */
3462 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3463 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3464
3465 hdr = (struct ieee80211_hdr *) beacon->data;
3466 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3467 IEEE80211_STYPE_PROBE_RESP);
3468 if (is_ap)
3469 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
3470 beacon->data,
3471 beacon->len,
3472 min_rate);
3473 else
3474 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
3475 CMD_TEMPL_PROBE_RESPONSE,
3476 beacon->data,
3477 beacon->len, 0,
3478 min_rate);
3479end_bcn:
3480 dev_kfree_skb(beacon);
3481 if (ret < 0)
3482 goto out;
3483
3484out:
3485 return ret;
3486}
3487
Arik Nemtsove78a2872010-10-16 19:07:21 +02003488static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3489 struct ieee80211_vif *vif,
3490 struct ieee80211_bss_conf *bss_conf,
3491 u32 changed)
3492{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003493 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003494 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 int ret = 0;
3496
3497 if ((changed & BSS_CHANGED_BEACON_INT)) {
3498 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3499 bss_conf->beacon_int);
3500
Eliad Peller6a899792011-10-05 11:55:58 +02003501 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003502 }
3503
Arik Nemtsov560f002412011-11-08 18:46:54 +02003504 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3505 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Luciano Coelho62c2e572012-05-10 12:14:04 +03003506
3507 wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003508 }
3509
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 if ((changed & BSS_CHANGED_BEACON)) {
Luciano Coelho62c2e572012-05-10 12:14:04 +03003511 ret = wlcore_set_beacon_template(wl, vif, is_ap);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003512 if (ret < 0)
3513 goto out;
3514 }
3515
3516out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003517 if (ret != 0)
3518 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003519 return ret;
3520}
3521
3522/* AP mode changes */
3523static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003524 struct ieee80211_vif *vif,
3525 struct ieee80211_bss_conf *bss_conf,
3526 u32 changed)
3527{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003528 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3532 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003533
Eliad Peller87fbcb02011-10-05 11:55:41 +02003534 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003535 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003536 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003537 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538
Eliad Peller87fbcb02011-10-05 11:55:41 +02003539 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003540 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003541 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003543 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003544
Eliad Peller784f6942011-10-05 11:55:39 +02003545 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003546 if (ret < 0)
3547 goto out;
Luciano Coelho62c2e572012-05-10 12:14:04 +03003548
3549 ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
3550 if (ret < 0)
3551 goto out;
3552
3553 ret = wlcore_set_beacon_template(wl, vif, true);
3554 if (ret < 0)
3555 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003556 }
3557
Arik Nemtsove78a2872010-10-16 19:07:21 +02003558 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3559 if (ret < 0)
3560 goto out;
3561
3562 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3563 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003564 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003565 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003566 if (ret < 0)
3567 goto out;
3568
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003569 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003570 if (ret < 0)
3571 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003572
Eliad Peller53d40d02011-10-10 10:13:02 +02003573 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003574 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 }
3576 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003577 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003578 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 if (ret < 0)
3580 goto out;
3581
Eliad Peller53d40d02011-10-10 10:13:02 +02003582 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003583 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3584 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003585 wl1271_debug(DEBUG_AP, "stopped AP");
3586 }
3587 }
3588 }
3589
Eliad Peller0603d892011-10-05 11:55:51 +02003590 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003591 if (ret < 0)
3592 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003593
3594 /* Handle HT information change */
3595 if ((changed & BSS_CHANGED_HT) &&
3596 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003597 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003598 bss_conf->ht_operation_mode);
3599 if (ret < 0) {
3600 wl1271_warning("Set ht information failed %d", ret);
3601 goto out;
3602 }
3603 }
3604
Arik Nemtsove78a2872010-10-16 19:07:21 +02003605out:
3606 return;
3607}
3608
3609/* STA/IBSS mode changes */
3610static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3611 struct ieee80211_vif *vif,
3612 struct ieee80211_bss_conf *bss_conf,
3613 u32 changed)
3614{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003615 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003616 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003617 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003618 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003619 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003620 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003621 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003622 bool sta_exists = false;
3623 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003624
3625 if (is_ibss) {
3626 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3627 changed);
3628 if (ret < 0)
3629 goto out;
3630 }
3631
Eliad Peller227e81e2011-08-14 13:17:26 +03003632 if (changed & BSS_CHANGED_IBSS) {
3633 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003634 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003635 ibss_joined = true;
3636 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003637 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
Eliad Peller349345a2012-03-04 10:55:45 +02003638 &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02003639 wl1271_unjoin(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003640 }
3641 }
3642
3643 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003644 do_join = true;
3645
3646 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003647 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003648 do_join = true;
3649
Eliad Peller227e81e2011-08-14 13:17:26 +03003650 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003651 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3652 bss_conf->enable_beacon ? "enabled" : "disabled");
3653
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003654 do_join = true;
3655 }
3656
Eliad Peller349345a2012-03-04 10:55:45 +02003657 if (changed & BSS_CHANGED_IDLE && !is_ibss) {
Eliad Pellerc31e4942011-10-23 08:21:55 +02003658 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3659 if (ret < 0)
3660 wl1271_warning("idle mode change failed %d", ret);
3661 }
3662
Arik Nemtsove78a2872010-10-16 19:07:21 +02003663 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003664 bool enable = false;
3665 if (bss_conf->cqm_rssi_thold)
3666 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003667 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003668 bss_conf->cqm_rssi_thold,
3669 bss_conf->cqm_rssi_hyst);
3670 if (ret < 0)
3671 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003672 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003673 }
3674
Eliad Peller446f5ca2012-03-12 14:53:04 +02003675 if (changed & BSS_CHANGED_BSSID)
Eliad Pellercdf09492011-10-05 11:55:44 +02003676 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003677 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003678 if (ret < 0)
3679 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003680
Eliad Peller784f6942011-10-05 11:55:39 +02003681 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003682 if (ret < 0)
3683 goto out;
Eliad Pellerfa287b82010-12-26 09:27:50 +01003684 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003685
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003686 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3687 rcu_read_lock();
3688 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3689 if (!sta)
3690 goto sta_not_found;
3691
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003692 /* save the supp_rates of the ap */
3693 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3694 if (sta->ht_cap.ht_supported)
3695 sta_rate_set |=
Arik Nemtsovb3a47ee2012-05-10 12:13:33 +03003696 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
3697 (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003698 sta_ht_cap = sta->ht_cap;
3699 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003700
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003701sta_not_found:
3702 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003703 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003704
Arik Nemtsove78a2872010-10-16 19:07:21 +02003705 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003707 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003708 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003709 wlvif->aid = bss_conf->aid;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03003710 wlvif->channel_type = bss_conf->channel_type;
Eliad Peller66677762012-03-04 10:55:53 +02003711 wlvif->beacon_int = bss_conf->beacon_int;
Eliad Peller446f5ca2012-03-12 14:53:04 +02003712 do_join = true;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003713 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003714
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003715 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003716 * use basic rates from AP, and determine lowest rate
3717 * to use with control frames.
3718 */
3719 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003720 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003721 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003722 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003723 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003724 wl1271_tx_min_rate_get(wl,
3725 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003726 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003727 wlvif->rate_set =
3728 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003729 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003730 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003731 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003732 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003733 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003734
3735 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003736 * with wl1271, we don't need to update the
3737 * beacon_int and dtim_period, because the firmware
3738 * updates it by itself when the first beacon is
3739 * received after a join.
3740 */
Eliad Peller6840e372011-10-05 11:55:50 +02003741 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003742 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003743 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003744
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003745 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003746 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003747 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003748 dev_kfree_skb(wlvif->probereq);
3749 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003750 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003751 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003752 ieoffset = offsetof(struct ieee80211_mgmt,
3753 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003754 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003755
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003756 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003757 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003758 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003759 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003760 } else {
3761 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003762 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003763 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3764 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003765 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003766 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3767 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003768 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003769
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003770 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003771 dev_kfree_skb(wlvif->probereq);
3772 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003773
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003774 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003775 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003776 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003777 wl1271_tx_min_rate_get(wl,
3778 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003779 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003780 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003781 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003782
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003783 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003784 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003785
3786 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003787 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003788 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003789 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003790
3791 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003792 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003793 /*
3794 * we might have to disable roc, if there was
3795 * no IF_OPER_UP notification.
3796 */
3797 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003798 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003799 if (ret < 0)
3800 goto out;
3801 }
3802 /*
3803 * (we also need to disable roc in case of
3804 * roaming on the same channel. until we will
3805 * have a better flow...)
3806 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003807 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3808 ret = wl12xx_croc(wl,
3809 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003810 if (ret < 0)
3811 goto out;
3812 }
3813
Eliad Peller0603d892011-10-05 11:55:51 +02003814 wl1271_unjoin(wl, wlvif);
Eliad Peller8a6a84a2012-03-04 10:55:46 +02003815 if (!bss_conf->idle)
Eliad Peller679a6732011-10-11 11:55:44 +02003816 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003817 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003818 }
3819 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003820
Eliad Pellerd192d262011-05-24 14:33:08 +03003821 if (changed & BSS_CHANGED_IBSS) {
3822 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3823 bss_conf->ibss_joined);
3824
3825 if (bss_conf->ibss_joined) {
3826 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003827 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003828 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003829 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003830 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003831 wl1271_tx_min_rate_get(wl,
3832 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003833
Shahar Levi06b660e2011-09-05 13:54:36 +03003834 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003835 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3836 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003837 if (ret < 0)
3838 goto out;
3839 }
3840 }
3841
Eliad Peller0603d892011-10-05 11:55:51 +02003842 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003843 if (ret < 0)
3844 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003845
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003846 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003847 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003848 if (ret < 0) {
3849 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003850 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003851 }
Eliad Peller251c1772011-08-14 13:17:17 +03003852
3853 /* ROC until connected (after EAPOL exchange) */
3854 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003855 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003856 if (ret < 0)
3857 goto out;
3858
Eliad Peller9fd6f212012-03-04 10:55:48 +02003859 if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
3860 wl12xx_set_authorized(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003861 }
3862 /*
3863 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003864 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003865 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003866 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003867 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003868 if (ret < 0)
3869 goto out;
3870 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003871 }
3872
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003873 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003874 if (sta_exists) {
3875 if ((changed & BSS_CHANGED_HT) &&
3876 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003877 ret = wl1271_acx_set_ht_capabilities(wl,
3878 &sta_ht_cap,
3879 true,
Eliad Peller154da672011-10-05 11:55:53 +02003880 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003881 if (ret < 0) {
3882 wl1271_warning("Set ht cap true failed %d",
3883 ret);
3884 goto out;
3885 }
3886 }
3887 /* handle new association without HT and disassociation */
3888 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003889 ret = wl1271_acx_set_ht_capabilities(wl,
3890 &sta_ht_cap,
3891 false,
Eliad Peller154da672011-10-05 11:55:53 +02003892 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003893 if (ret < 0) {
3894 wl1271_warning("Set ht cap false failed %d",
3895 ret);
3896 goto out;
3897 }
3898 }
3899 }
3900
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003901 /* Handle HT information change. Done after join. */
3902 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003903 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003904 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003905 bss_conf->ht_operation_mode);
3906 if (ret < 0) {
3907 wl1271_warning("Set ht information failed %d", ret);
3908 goto out;
3909 }
3910 }
3911
Eliad Peller76a74c82012-02-02 12:22:11 +02003912 /* Handle arp filtering. Done after join. */
3913 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3914 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3915 __be32 addr = bss_conf->arp_addr_list[0];
3916 wlvif->sta.qos = bss_conf->qos;
3917 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3918
3919 if (bss_conf->arp_addr_cnt == 1 &&
3920 bss_conf->arp_filter_enabled) {
3921 wlvif->ip_addr = addr;
3922 /*
3923 * The template should have been configured only upon
3924 * association. however, it seems that the correct ip
3925 * isn't being set (when sending), so we have to
3926 * reconfigure the template upon every ip change.
3927 */
3928 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3929 if (ret < 0) {
3930 wl1271_warning("build arp rsp failed: %d", ret);
3931 goto out;
3932 }
3933
3934 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3935 (ACX_ARP_FILTER_ARP_FILTERING |
3936 ACX_ARP_FILTER_AUTO_ARP),
3937 addr);
3938 } else {
3939 wlvif->ip_addr = 0;
3940 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
3941 }
3942
3943 if (ret < 0)
3944 goto out;
3945 }
3946
Arik Nemtsove78a2872010-10-16 19:07:21 +02003947out:
3948 return;
3949}
3950
3951static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3952 struct ieee80211_vif *vif,
3953 struct ieee80211_bss_conf *bss_conf,
3954 u32 changed)
3955{
3956 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003957 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3958 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003959 int ret;
3960
3961 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3962 (int)changed);
3963
Arik Nemtsov6b8bf5b2012-05-15 17:08:54 +03003964 /*
3965 * make sure to cancel pending disconnections if our association
3966 * state changed
3967 */
3968 if (!is_ap && (changed & BSS_CHANGED_ASSOC))
3969 cancel_delayed_work_sync(&wl->connection_loss_work);
3970
Eliad Pellerb515d832012-05-15 17:08:56 +03003971 if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
3972 !bss_conf->enable_beacon)
3973 wl1271_tx_flush(wl);
3974
Arik Nemtsove78a2872010-10-16 19:07:21 +02003975 mutex_lock(&wl->mutex);
3976
3977 if (unlikely(wl->state == WL1271_STATE_OFF))
3978 goto out;
3979
Eliad Peller10c8cd02011-10-10 10:13:06 +02003980 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3981 goto out;
3982
Ido Yariva6208652011-03-01 15:14:41 +02003983 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003984 if (ret < 0)
3985 goto out;
3986
3987 if (is_ap)
3988 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3989 else
3990 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3991
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003992 wl1271_ps_elp_sleep(wl);
3993
3994out:
3995 mutex_unlock(&wl->mutex);
3996}
3997
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003998static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3999 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02004000 const struct ieee80211_tx_queue_params *params)
4001{
4002 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004003 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004004 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004005 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004006
4007 mutex_lock(&wl->mutex);
4008
4009 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4010
Kalle Valo4695dc92010-03-18 12:26:38 +02004011 if (params->uapsd)
4012 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4013 else
4014 ps_scheme = CONF_PS_SCHEME_LEGACY;
4015
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004016 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004018
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004019 ret = wl1271_ps_elp_wakeup(wl);
4020 if (ret < 0)
4021 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004022
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004023 /*
4024 * the txop is confed in units of 32us by the mac80211,
4025 * we need us
4026 */
Eliad Peller0603d892011-10-05 11:55:51 +02004027 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004028 params->cw_min, params->cw_max,
4029 params->aifs, params->txop << 5);
4030 if (ret < 0)
4031 goto out_sleep;
4032
Eliad Peller0603d892011-10-05 11:55:51 +02004033 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004034 CONF_CHANNEL_TYPE_EDCF,
4035 wl1271_tx_get_queue(queue),
4036 ps_scheme, CONF_ACK_POLICY_LEGACY,
4037 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004038
4039out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004040 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004041
4042out:
4043 mutex_unlock(&wl->mutex);
4044
4045 return ret;
4046}
4047
Eliad Peller37a41b42011-09-21 14:06:11 +03004048static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4049 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004050{
4051
4052 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004053 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004054 u64 mactime = ULLONG_MAX;
4055 int ret;
4056
4057 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4058
4059 mutex_lock(&wl->mutex);
4060
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004061 if (unlikely(wl->state == WL1271_STATE_OFF))
4062 goto out;
4063
Ido Yariva6208652011-03-01 15:14:41 +02004064 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004065 if (ret < 0)
4066 goto out;
4067
Eliad Peller9c531142012-01-31 11:57:18 +02004068 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004069 if (ret < 0)
4070 goto out_sleep;
4071
4072out_sleep:
4073 wl1271_ps_elp_sleep(wl);
4074
4075out:
4076 mutex_unlock(&wl->mutex);
4077 return mactime;
4078}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004079
John W. Linvilleece550d2010-07-28 16:41:06 -04004080static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4081 struct survey_info *survey)
4082{
4083 struct wl1271 *wl = hw->priv;
4084 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004085
John W. Linvilleece550d2010-07-28 16:41:06 -04004086 if (idx != 0)
4087 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004088
John W. Linvilleece550d2010-07-28 16:41:06 -04004089 survey->channel = conf->channel;
4090 survey->filled = SURVEY_INFO_NOISE_DBM;
4091 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004092
John W. Linvilleece550d2010-07-28 16:41:06 -04004093 return 0;
4094}
4095
Arik Nemtsov409622e2011-02-23 00:22:29 +02004096static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004097 struct wl12xx_vif *wlvif,
4098 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004099{
4100 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004101 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004102
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004103
4104 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105 wl1271_warning("could not allocate HLID - too much stations");
4106 return -EBUSY;
4107 }
4108
4109 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004110 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4111 if (ret < 0) {
4112 wl1271_warning("could not allocate HLID - too many links");
4113 return -EBUSY;
4114 }
4115
4116 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004117 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004118 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119 return 0;
4120}
4121
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004123{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004124 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004125 return;
4126
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004127 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004128 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004129 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004130 __clear_bit(hlid, &wl->ap_ps_map);
4131 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004132 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004133 wl->active_sta_count--;
Arik Nemtsov55df5af2012-03-03 22:18:00 +02004134
4135 /*
4136 * rearm the tx watchdog when the last STA is freed - give the FW a
4137 * chance to return STA-buffered packets before complaining.
4138 */
4139 if (wl->active_sta_count == 0)
4140 wl12xx_rearm_tx_watchdog_locked(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004141}
4142
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004143static int wl12xx_sta_add(struct wl1271 *wl,
4144 struct wl12xx_vif *wlvif,
4145 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004146{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004147 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148 int ret = 0;
4149 u8 hlid;
4150
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4152
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004153 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004154 if (ret < 0)
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004155 return ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004157 wl_sta = (struct wl1271_station *)sta->drv_priv;
4158 hlid = wl_sta->hlid;
4159
Eliad Peller1b92f152011-10-10 10:13:09 +02004160 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004161 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004162 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004163
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004164 return ret;
4165}
4166
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004167static int wl12xx_sta_remove(struct wl1271 *wl,
4168 struct wl12xx_vif *wlvif,
4169 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004170{
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004171 struct wl1271_station *wl_sta;
4172 int ret = 0, id;
4173
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004174 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4175
4176 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004177 id = wl_sta->hlid;
4178 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004179 return -EINVAL;
4180
4181 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
4182 if (ret < 0)
4183 return ret;
4184
4185 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
4186 return ret;
4187}
4188
4189static int wl12xx_update_sta_state(struct wl1271 *wl,
4190 struct wl12xx_vif *wlvif,
4191 struct ieee80211_sta *sta,
4192 enum ieee80211_sta_state old_state,
4193 enum ieee80211_sta_state new_state)
4194{
4195 struct wl1271_station *wl_sta;
4196 u8 hlid;
4197 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
4198 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
4199 int ret;
4200
4201 wl_sta = (struct wl1271_station *)sta->drv_priv;
4202 hlid = wl_sta->hlid;
4203
4204 /* Add station (AP mode) */
4205 if (is_ap &&
4206 old_state == IEEE80211_STA_NOTEXIST &&
4207 new_state == IEEE80211_STA_NONE)
4208 return wl12xx_sta_add(wl, wlvif, sta);
4209
4210 /* Remove station (AP mode) */
4211 if (is_ap &&
4212 old_state == IEEE80211_STA_NONE &&
4213 new_state == IEEE80211_STA_NOTEXIST) {
4214 /* must not fail */
4215 wl12xx_sta_remove(wl, wlvif, sta);
4216 return 0;
4217 }
4218
4219 /* Authorize station (AP mode) */
4220 if (is_ap &&
4221 new_state == IEEE80211_STA_AUTHORIZED) {
4222 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4223 if (ret < 0)
4224 return ret;
4225
4226 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
4227 hlid);
4228 return ret;
4229 }
4230
Eliad Peller9fd6f212012-03-04 10:55:48 +02004231 /* Authorize station */
4232 if (is_sta &&
4233 new_state == IEEE80211_STA_AUTHORIZED) {
4234 set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
4235 return wl12xx_set_authorized(wl, wlvif);
4236 }
4237
4238 if (is_sta &&
4239 old_state == IEEE80211_STA_AUTHORIZED &&
4240 new_state == IEEE80211_STA_ASSOC) {
4241 clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
4242 return 0;
4243 }
4244
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004245 return 0;
4246}
4247
4248static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
4249 struct ieee80211_vif *vif,
4250 struct ieee80211_sta *sta,
4251 enum ieee80211_sta_state old_state,
4252 enum ieee80211_sta_state new_state)
4253{
4254 struct wl1271 *wl = hw->priv;
4255 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4256 int ret;
4257
4258 wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
4259 sta->aid, old_state, new_state);
4260
4261 mutex_lock(&wl->mutex);
4262
4263 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4264 ret = -EBUSY;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004265 goto out;
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004266 }
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004267
Ido Yariva6208652011-03-01 15:14:41 +02004268 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004269 if (ret < 0)
4270 goto out;
4271
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004272 ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004273
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004274 wl1271_ps_elp_sleep(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004275out:
4276 mutex_unlock(&wl->mutex);
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004277 if (new_state < old_state)
4278 return 0;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004279 return ret;
4280}
4281
Luciano Coelho4623ec72011-03-21 19:26:41 +02004282static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4283 struct ieee80211_vif *vif,
4284 enum ieee80211_ampdu_mlme_action action,
4285 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4286 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004287{
4288 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004289 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004290 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004291 u8 hlid, *ba_bitmap;
4292
4293 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4294 tid);
4295
4296 /* sanity check - the fields in FW are only 8bits wide */
4297 if (WARN_ON(tid > 0xFF))
4298 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004299
4300 mutex_lock(&wl->mutex);
4301
4302 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4303 ret = -EAGAIN;
4304 goto out;
4305 }
4306
Eliad Peller536129c2011-10-05 11:55:45 +02004307 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004308 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004309 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004310 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004311 struct wl1271_station *wl_sta;
4312
4313 wl_sta = (struct wl1271_station *)sta->drv_priv;
4314 hlid = wl_sta->hlid;
4315 ba_bitmap = &wl->links[hlid].ba_bitmap;
4316 } else {
4317 ret = -EINVAL;
4318 goto out;
4319 }
4320
Ido Yariva6208652011-03-01 15:14:41 +02004321 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004322 if (ret < 0)
4323 goto out;
4324
Shahar Levi70559a02011-05-22 16:10:22 +03004325 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4326 tid, action);
4327
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004328 switch (action) {
4329 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004330 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004331 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004332 break;
4333 }
4334
4335 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4336 ret = -EBUSY;
4337 wl1271_error("exceeded max RX BA sessions");
4338 break;
4339 }
4340
4341 if (*ba_bitmap & BIT(tid)) {
4342 ret = -EINVAL;
4343 wl1271_error("cannot enable RX BA session on active "
4344 "tid: %d", tid);
4345 break;
4346 }
4347
4348 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4349 hlid);
4350 if (!ret) {
4351 *ba_bitmap |= BIT(tid);
4352 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004353 }
4354 break;
4355
4356 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004357 if (!(*ba_bitmap & BIT(tid))) {
4358 ret = -EINVAL;
4359 wl1271_error("no active RX BA session on tid: %d",
4360 tid);
4361 break;
4362 }
4363
4364 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4365 hlid);
4366 if (!ret) {
4367 *ba_bitmap &= ~BIT(tid);
4368 wl->ba_rx_session_count--;
4369 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004370 break;
4371
4372 /*
4373 * The BA initiator session management in FW independently.
4374 * Falling break here on purpose for all TX APDU commands.
4375 */
4376 case IEEE80211_AMPDU_TX_START:
4377 case IEEE80211_AMPDU_TX_STOP:
4378 case IEEE80211_AMPDU_TX_OPERATIONAL:
4379 ret = -EINVAL;
4380 break;
4381
4382 default:
4383 wl1271_error("Incorrect ampdu action id=%x\n", action);
4384 ret = -EINVAL;
4385 }
4386
4387 wl1271_ps_elp_sleep(wl);
4388
4389out:
4390 mutex_unlock(&wl->mutex);
4391
4392 return ret;
4393}
4394
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004395static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4396 struct ieee80211_vif *vif,
4397 const struct cfg80211_bitrate_mask *mask)
4398{
Eliad Peller83587502011-10-10 10:12:53 +02004399 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004400 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004401 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004402
4403 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4404 mask->control[NL80211_BAND_2GHZ].legacy,
4405 mask->control[NL80211_BAND_5GHZ].legacy);
4406
4407 mutex_lock(&wl->mutex);
4408
4409 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004410 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004411 wl1271_tx_enabled_rates_get(wl,
4412 mask->control[i].legacy,
4413 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004414
4415 if (unlikely(wl->state == WL1271_STATE_OFF))
4416 goto out;
4417
4418 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4419 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4420
4421 ret = wl1271_ps_elp_wakeup(wl);
4422 if (ret < 0)
4423 goto out;
4424
4425 wl1271_set_band_rate(wl, wlvif);
4426 wlvif->basic_rate =
4427 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4428 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4429
4430 wl1271_ps_elp_sleep(wl);
4431 }
4432out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004433 mutex_unlock(&wl->mutex);
4434
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004435 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004436}
4437
Shahar Levi6d158ff2011-09-08 13:01:33 +03004438static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4439 struct ieee80211_channel_switch *ch_switch)
4440{
4441 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004442 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004443 int ret;
4444
4445 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4446
Arik Nemtsovb9239b62012-02-28 00:41:33 +02004447 wl1271_tx_flush(wl);
4448
Shahar Levi6d158ff2011-09-08 13:01:33 +03004449 mutex_lock(&wl->mutex);
4450
4451 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004452 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4453 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4454 ieee80211_chswitch_done(vif, false);
4455 }
4456 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004457 }
4458
4459 ret = wl1271_ps_elp_wakeup(wl);
4460 if (ret < 0)
4461 goto out;
4462
Eliad Peller52630c52011-10-10 10:13:08 +02004463 /* TODO: change mac80211 to pass vif as param */
4464 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004465 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004466
Eliad Peller52630c52011-10-10 10:13:08 +02004467 if (!ret)
4468 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4469 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004470
4471 wl1271_ps_elp_sleep(wl);
4472
4473out:
4474 mutex_unlock(&wl->mutex);
4475}
4476
Arik Nemtsov33437892011-04-26 23:35:39 +03004477static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4478{
4479 struct wl1271 *wl = hw->priv;
4480 bool ret = false;
4481
4482 mutex_lock(&wl->mutex);
4483
4484 if (unlikely(wl->state == WL1271_STATE_OFF))
4485 goto out;
4486
4487 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004488 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004489out:
4490 mutex_unlock(&wl->mutex);
4491
4492 return ret;
4493}
4494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004495/* can't be const, mac80211 writes to this */
4496static struct ieee80211_rate wl1271_rates[] = {
4497 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004498 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4499 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004500 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004501 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4502 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004503 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4504 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004505 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4506 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004507 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4508 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004509 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4510 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004511 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4512 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004513 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4514 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004515 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004516 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4517 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004518 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004519 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4520 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004522 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4523 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004524 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004525 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4526 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004527 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004528 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004530 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004531 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004533 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004534 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004536};
4537
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004538/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004539static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004540 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004541 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004542 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4543 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4544 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004545 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004546 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4547 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4548 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004549 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004550 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4551 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4552 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004553 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004554};
4555
4556/* can't be const, mac80211 writes to this */
4557static struct ieee80211_supported_band wl1271_band_2ghz = {
4558 .channels = wl1271_channels,
4559 .n_channels = ARRAY_SIZE(wl1271_channels),
4560 .bitrates = wl1271_rates,
4561 .n_bitrates = ARRAY_SIZE(wl1271_rates),
4562};
4563
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004564/* 5 GHz data rates for WL1273 */
4565static struct ieee80211_rate wl1271_rates_5ghz[] = {
4566 { .bitrate = 60,
4567 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4568 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4569 { .bitrate = 90,
4570 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4571 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4572 { .bitrate = 120,
4573 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4574 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4575 { .bitrate = 180,
4576 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4577 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4578 { .bitrate = 240,
4579 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4580 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4581 { .bitrate = 360,
4582 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4583 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4584 { .bitrate = 480,
4585 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4586 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4587 { .bitrate = 540,
4588 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4589 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4590};
4591
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004592/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004593static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004594 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4595 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4596 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4597 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4598 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4599 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4600 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4601 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4602 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4603 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4604 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4605 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4606 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4607 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4608 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4609 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4610 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4611 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4612 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4613 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4614 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4615 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4616 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4617 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4618 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4619 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4620 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4621 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4622 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4623 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4624 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4625 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4626 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4627 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004628};
4629
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004630static struct ieee80211_supported_band wl1271_band_5ghz = {
4631 .channels = wl1271_channels_5ghz,
4632 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4633 .bitrates = wl1271_rates_5ghz,
4634 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004635};
4636
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004637static const struct ieee80211_ops wl1271_ops = {
4638 .start = wl1271_op_start,
4639 .stop = wl1271_op_stop,
4640 .add_interface = wl1271_op_add_interface,
4641 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004642 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004643#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004644 .suspend = wl1271_op_suspend,
4645 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004646#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004647 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004648 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004649 .configure_filter = wl1271_op_configure_filter,
4650 .tx = wl1271_op_tx,
4651 .set_key = wl1271_op_set_key,
4652 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004653 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004654 .sched_scan_start = wl1271_op_sched_scan_start,
4655 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004656 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004657 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004658 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004659 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004660 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004661 .get_survey = wl1271_op_get_survey,
Eliad Peller2d6cf2b2012-03-04 10:55:47 +02004662 .sta_state = wl12xx_op_sta_state,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004663 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004664 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004665 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004666 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004667 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004668};
4669
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004670
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004671u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004672{
4673 u8 idx;
4674
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004675 BUG_ON(band >= 2);
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004676
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004677 if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678 wl1271_error("Illegal RX rate from HW: %d", rate);
4679 return 0;
4680 }
4681
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02004682 idx = wl->band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004683 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4684 wl1271_error("Unsupported RX rate from HW: %d", rate);
4685 return 0;
4686 }
4687
4688 return idx;
4689}
4690
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004691static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4692 struct device_attribute *attr,
4693 char *buf)
4694{
4695 struct wl1271 *wl = dev_get_drvdata(dev);
4696 ssize_t len;
4697
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004698 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004699
4700 mutex_lock(&wl->mutex);
4701 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4702 wl->sg_enabled);
4703 mutex_unlock(&wl->mutex);
4704
4705 return len;
4706
4707}
4708
4709static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4710 struct device_attribute *attr,
4711 const char *buf, size_t count)
4712{
4713 struct wl1271 *wl = dev_get_drvdata(dev);
4714 unsigned long res;
4715 int ret;
4716
Luciano Coelho6277ed62011-04-01 17:49:54 +03004717 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004718 if (ret < 0) {
4719 wl1271_warning("incorrect value written to bt_coex_mode");
4720 return count;
4721 }
4722
4723 mutex_lock(&wl->mutex);
4724
4725 res = !!res;
4726
4727 if (res == wl->sg_enabled)
4728 goto out;
4729
4730 wl->sg_enabled = res;
4731
4732 if (wl->state == WL1271_STATE_OFF)
4733 goto out;
4734
Ido Yariva6208652011-03-01 15:14:41 +02004735 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004736 if (ret < 0)
4737 goto out;
4738
4739 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4740 wl1271_ps_elp_sleep(wl);
4741
4742 out:
4743 mutex_unlock(&wl->mutex);
4744 return count;
4745}
4746
4747static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4748 wl1271_sysfs_show_bt_coex_state,
4749 wl1271_sysfs_store_bt_coex_state);
4750
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004751static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4752 struct device_attribute *attr,
4753 char *buf)
4754{
4755 struct wl1271 *wl = dev_get_drvdata(dev);
4756 ssize_t len;
4757
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004758 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004759
4760 mutex_lock(&wl->mutex);
4761 if (wl->hw_pg_ver >= 0)
4762 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4763 else
4764 len = snprintf(buf, len, "n/a\n");
4765 mutex_unlock(&wl->mutex);
4766
4767 return len;
4768}
4769
Gery Kahn6f07b722011-07-18 14:21:49 +03004770static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004771 wl1271_sysfs_show_hw_pg_ver, NULL);
4772
Ido Yariv95dac04f2011-06-06 14:57:06 +03004773static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4774 struct bin_attribute *bin_attr,
4775 char *buffer, loff_t pos, size_t count)
4776{
4777 struct device *dev = container_of(kobj, struct device, kobj);
4778 struct wl1271 *wl = dev_get_drvdata(dev);
4779 ssize_t len;
4780 int ret;
4781
4782 ret = mutex_lock_interruptible(&wl->mutex);
4783 if (ret < 0)
4784 return -ERESTARTSYS;
4785
4786 /* Let only one thread read the log at a time, blocking others */
4787 while (wl->fwlog_size == 0) {
4788 DEFINE_WAIT(wait);
4789
4790 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4791 &wait,
4792 TASK_INTERRUPTIBLE);
4793
4794 if (wl->fwlog_size != 0) {
4795 finish_wait(&wl->fwlog_waitq, &wait);
4796 break;
4797 }
4798
4799 mutex_unlock(&wl->mutex);
4800
4801 schedule();
4802 finish_wait(&wl->fwlog_waitq, &wait);
4803
4804 if (signal_pending(current))
4805 return -ERESTARTSYS;
4806
4807 ret = mutex_lock_interruptible(&wl->mutex);
4808 if (ret < 0)
4809 return -ERESTARTSYS;
4810 }
4811
4812 /* Check if the fwlog is still valid */
4813 if (wl->fwlog_size < 0) {
4814 mutex_unlock(&wl->mutex);
4815 return 0;
4816 }
4817
4818 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4819 len = min(count, (size_t)wl->fwlog_size);
4820 wl->fwlog_size -= len;
4821 memcpy(buffer, wl->fwlog, len);
4822
4823 /* Make room for new messages */
4824 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4825
4826 mutex_unlock(&wl->mutex);
4827
4828 return len;
4829}
4830
4831static struct bin_attribute fwlog_attr = {
4832 .attr = {.name = "fwlog", .mode = S_IRUSR},
4833 .read = wl1271_sysfs_read_fwlog,
4834};
4835
Luciano Coelho22479972012-05-16 06:00:00 +03004836static void wl1271_connection_loss_work(struct work_struct *work)
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03004837{
4838 struct delayed_work *dwork;
4839 struct wl1271 *wl;
4840 struct ieee80211_vif *vif;
4841 struct wl12xx_vif *wlvif;
4842
4843 dwork = container_of(work, struct delayed_work, work);
4844 wl = container_of(dwork, struct wl1271, connection_loss_work);
4845
4846 wl1271_info("Connection loss work.");
4847
4848 mutex_lock(&wl->mutex);
4849
4850 if (unlikely(wl->state == WL1271_STATE_OFF))
4851 goto out;
4852
4853 /* Call mac80211 connection loss */
4854 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4855 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
4856 goto out;
4857 vif = wl12xx_wlvif_to_vif(wlvif);
4858 ieee80211_connection_loss(vif);
4859 }
4860out:
4861 mutex_unlock(&wl->mutex);
4862}
4863
Luciano Coelho5e037e72011-12-23 09:32:17 +02004864static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4865 u32 oui, u32 nic, int n)
4866{
4867 int i;
4868
4869 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4870 oui, nic, n);
4871
4872 if (nic + n - 1 > 0xffffff)
4873 wl1271_warning("NIC part of the MAC address wraps around!");
4874
4875 for (i = 0; i < n; i++) {
4876 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4877 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4878 wl->addresses[i].addr[2] = (u8) oui;
4879 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4880 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4881 wl->addresses[i].addr[5] = (u8) nic;
4882 nic++;
4883 }
4884
4885 wl->hw->wiphy->n_addresses = n;
4886 wl->hw->wiphy->addresses = wl->addresses;
4887}
4888
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004889static int wl12xx_get_hw_info(struct wl1271 *wl)
4890{
4891 int ret;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004892
4893 ret = wl12xx_set_power_on(wl);
4894 if (ret < 0)
4895 goto out;
4896
Luciano Coelho00782132011-11-29 13:38:37 +02004897 wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004898
Luciano Coelho00782132011-11-29 13:38:37 +02004899 wl->fuse_oui_addr = 0;
4900 wl->fuse_nic_addr = 0;
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004901
Luciano Coelho4ded91c2012-04-11 10:54:52 +03004902 wl->hw_pg_ver = wl->ops->get_pg_ver(wl);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004903
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03004904 if (wl->ops->get_mac)
4905 wl->ops->get_mac(wl);
Luciano Coelho5e037e72011-12-23 09:32:17 +02004906
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004907 wl1271_power_off(wl);
4908out:
4909 return ret;
4910}
4911
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004912static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913{
4914 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004915 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004916
4917 if (wl->mac80211_registered)
4918 return 0;
4919
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004920 ret = wl1271_fetch_nvs(wl);
4921 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004922 /* NOTE: The wl->nvs->nvs element must be first, in
4923 * order to simplify the casting, we assume it is at
4924 * the beginning of the wl->nvs structure.
4925 */
4926 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004927
Luciano Coelho5e037e72011-12-23 09:32:17 +02004928 oui_addr =
4929 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4930 nic_addr =
4931 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004932 }
4933
Luciano Coelho5e037e72011-12-23 09:32:17 +02004934 /* if the MAC address is zeroed in the NVS derive from fuse */
4935 if (oui_addr == 0 && nic_addr == 0) {
4936 oui_addr = wl->fuse_oui_addr;
4937 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4938 nic_addr = wl->fuse_nic_addr + 1;
4939 }
4940
4941 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004942
4943 ret = ieee80211_register_hw(wl->hw);
4944 if (ret < 0) {
4945 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004946 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004947 }
4948
4949 wl->mac80211_registered = true;
4950
Eliad Pellerd60080a2010-11-24 12:53:16 +02004951 wl1271_debugfs_init(wl);
4952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004953 wl1271_notice("loaded");
4954
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004955out:
4956 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004957}
4958
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004959static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004960{
Eliad Peller3fcdab72012-02-06 12:47:54 +02004961 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02004962 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004963
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004964 ieee80211_unregister_hw(wl->hw);
4965 wl->mac80211_registered = false;
4966
4967}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004968
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004969static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004970{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004971 static const u32 cipher_suites[] = {
4972 WLAN_CIPHER_SUITE_WEP40,
4973 WLAN_CIPHER_SUITE_WEP104,
4974 WLAN_CIPHER_SUITE_TKIP,
4975 WLAN_CIPHER_SUITE_CCMP,
4976 WL1271_CIPHER_SUITE_GEM,
4977 };
4978
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004979 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02004980 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004981 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982
4983 /* unit us */
4984 /* FIXME: find a proper value */
4985 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004986 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987
4988 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004989 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02004990 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004991 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004992 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004993 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004994 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004995 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004996 IEEE80211_HW_AP_LINK_PS |
4997 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02004998 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
4999 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005001 wl->hw->wiphy->cipher_suites = cipher_suites;
5002 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5003
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005004 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005005 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5006 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005007 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005008 wl->hw->wiphy->max_sched_scan_ssids = 16;
5009 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005010 /*
5011 * Maximum length of elements in scanning probe request templates
5012 * should be the maximum length possible for a template, without
5013 * the IEEE80211 header of the template
5014 */
Ido Reisc08e3712012-02-02 13:54:27 +02005015 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005016 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005017
Ido Reisc08e3712012-02-02 13:54:27 +02005018 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005019 sizeof(struct ieee80211_header);
5020
Johannes Berg81ddbb52012-03-26 18:47:18 +02005021 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
5022 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
Eliad Peller1ec23f72011-08-25 14:26:54 +03005023
Luciano Coelho4a31c112011-03-21 23:16:14 +02005024 /* make sure all our channels fit in the scanned_ch bitmask */
5025 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5026 ARRAY_SIZE(wl1271_channels_5ghz) >
5027 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005028 /*
5029 * We keep local copies of the band structs because we need to
5030 * modify them on a per-device basis.
5031 */
5032 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5033 sizeof(wl1271_band_2ghz));
Arik Nemtsov4a589a62011-12-13 13:20:44 +02005034 memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
5035 sizeof(wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005036 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5037 sizeof(wl1271_band_5ghz));
Arik Nemtsov4a589a62011-12-13 13:20:44 +02005038 memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
5039 sizeof(wl->ht_cap));
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005040
5041 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5042 &wl->bands[IEEE80211_BAND_2GHZ];
5043 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5044 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005045
Kalle Valo12bd8942010-03-18 12:26:33 +02005046 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005047 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005048
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005049 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5050
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005051 /* the FW answers probe-requests in AP-mode */
5052 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5053 wl->hw->wiphy->probe_resp_offload =
5054 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5055 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5056 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5057
Felipe Balbia390e852011-10-06 10:07:44 +03005058 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005059
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005060 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005061 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005062
Arik Nemtsovba421f82012-01-06 00:05:51 +02005063 wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size;
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005065 return 0;
5066}
5067
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005068#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005069
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005070struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005071{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005072 struct ieee80211_hw *hw;
5073 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005074 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005075 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005076
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005077 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005078
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005079 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5080 if (!hw) {
5081 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005082 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005083 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005084 }
5085
5086 wl = hw->priv;
5087 memset(wl, 0, sizeof(*wl));
5088
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005089 wl->priv = kzalloc(priv_size, GFP_KERNEL);
5090 if (!wl->priv) {
5091 wl1271_error("could not alloc wl priv");
5092 ret = -ENOMEM;
5093 goto err_priv_alloc;
5094 }
5095
Eliad Peller87627212011-10-10 10:12:54 +02005096 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005097
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005098 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005099
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005100 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005101 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005102 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5103
Ido Yariva6208652011-03-01 15:14:41 +02005104 skb_queue_head_init(&wl->deferred_rx_queue);
5105 skb_queue_head_init(&wl->deferred_tx_queue);
5106
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005107 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005108 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005109 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5110 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5111 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Arik Nemtsov55df5af2012-03-03 22:18:00 +02005112 INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
Bartosz.Markowski@tieto.com5f561f62012-04-26 10:35:07 +03005113 INIT_DELAYED_WORK(&wl->connection_loss_work,
5114 wl1271_connection_loss_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005115
Eliad Peller92ef8962011-06-07 12:50:46 +03005116 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5117 if (!wl->freezable_wq) {
5118 ret = -ENOMEM;
5119 goto err_hw;
5120 }
5121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005122 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005123 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005124 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005125 wl->band = IEEE80211_BAND_2GHZ;
Arik Nemtsov83d08d32012-05-10 12:13:30 +03005126 wl->channel_type = NL80211_CHAN_NO_HT;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005127 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005128 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005129 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005130 wl->ap_ps_map = 0;
5131 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005132 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005133 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005134 wl->sched_scanning = false;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005135 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005136 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005137 wl->fwlog_size = 0;
5138 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005139
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005140 /* The system link is always allocated */
5141 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5142
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005143 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Arik Nemtsov72b06242011-12-07 21:21:51 +02005144 for (i = 0; i < wl->num_tx_desc; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005145 wl->tx_frames[i] = NULL;
5146
5147 spin_lock_init(&wl->wl_lock);
5148
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005149 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005150 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005151 mutex_init(&wl->mutex);
5152
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005153 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5154 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5155 if (!wl->aggr_buf) {
5156 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005157 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005158 }
5159
Ido Yariv990f5de2011-03-31 10:06:59 +02005160 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5161 if (!wl->dummy_packet) {
5162 ret = -ENOMEM;
5163 goto err_aggr;
5164 }
5165
Ido Yariv95dac04f2011-06-06 14:57:06 +03005166 /* Allocate one page for the FW log */
5167 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5168 if (!wl->fwlog) {
5169 ret = -ENOMEM;
5170 goto err_dummy_packet;
5171 }
5172
Luciano Coelhofd492ed2012-05-03 10:31:02 +03005173 wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
Mircea Gherzan690142e2012-03-17 18:41:53 +01005174 if (!wl->mbox) {
5175 ret = -ENOMEM;
5176 goto err_fwlog;
5177 }
5178
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005179 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005180
Mircea Gherzan690142e2012-03-17 18:41:53 +01005181err_fwlog:
5182 free_page((unsigned long)wl->fwlog);
5183
Ido Yariv990f5de2011-03-31 10:06:59 +02005184err_dummy_packet:
5185 dev_kfree_skb(wl->dummy_packet);
5186
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005187err_aggr:
5188 free_pages((unsigned long)wl->aggr_buf, order);
5189
Eliad Peller92ef8962011-06-07 12:50:46 +03005190err_wq:
5191 destroy_workqueue(wl->freezable_wq);
5192
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005193err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005194 wl1271_debugfs_exit(wl);
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005195 kfree(wl->priv);
5196
5197err_priv_alloc:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005198 ieee80211_free_hw(hw);
5199
5200err_hw_alloc:
5201
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005202 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005203}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005204EXPORT_SYMBOL_GPL(wlcore_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005205
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005206int wlcore_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005207{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005208 /* Unblock any fwlog readers */
5209 mutex_lock(&wl->mutex);
5210 wl->fwlog_size = -1;
5211 wake_up_interruptible_all(&wl->fwlog_waitq);
5212 mutex_unlock(&wl->mutex);
5213
Felipe Balbif79f8902011-10-06 13:05:25 +03005214 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005215
Felipe Balbif79f8902011-10-06 13:05:25 +03005216 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005217
Felipe Balbif79f8902011-10-06 13:05:25 +03005218 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005219 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005220 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005221 free_pages((unsigned long)wl->aggr_buf,
5222 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005223
5224 wl1271_debugfs_exit(wl);
5225
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005226 vfree(wl->fw);
5227 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005228 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005229 kfree(wl->nvs);
5230 wl->nvs = NULL;
5231
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03005232 kfree(wl->fw_status_1);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005233 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005234 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005235
Arik Nemtsov96e0c682011-12-07 21:09:03 +02005236 kfree(wl->priv);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005237 ieee80211_free_hw(wl->hw);
5238
5239 return 0;
5240}
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005241EXPORT_SYMBOL_GPL(wlcore_free_hw);
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005242
Felipe Balbia390e852011-10-06 10:07:44 +03005243static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5244{
5245 struct wl1271 *wl = cookie;
5246 unsigned long flags;
5247
5248 wl1271_debug(DEBUG_IRQ, "IRQ");
5249
5250 /* complete the ELP completion */
5251 spin_lock_irqsave(&wl->wl_lock, flags);
5252 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5253 if (wl->elp_compl) {
5254 complete(wl->elp_compl);
5255 wl->elp_compl = NULL;
5256 }
5257
5258 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5259 /* don't enqueue a work right now. mark it as pending */
5260 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5261 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5262 disable_irq_nosync(wl->irq);
5263 pm_wakeup_event(wl->dev, 0);
5264 spin_unlock_irqrestore(&wl->wl_lock, flags);
5265 return IRQ_HANDLED;
5266 }
5267 spin_unlock_irqrestore(&wl->wl_lock, flags);
5268
5269 return IRQ_WAKE_THREAD;
5270}
5271
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005272int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03005273{
Felipe Balbia390e852011-10-06 10:07:44 +03005274 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
Felipe Balbia390e852011-10-06 10:07:44 +03005275 unsigned long irqflags;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005276 int ret;
Felipe Balbia390e852011-10-06 10:07:44 +03005277
Luciano Coelho25a43d72011-11-21 20:37:14 +02005278 if (!wl->ops || !wl->ptable) {
Luciano Coelhoc31be252011-11-21 19:25:24 +02005279 ret = -EINVAL;
5280 goto out_free_hw;
Felipe Balbia390e852011-10-06 10:07:44 +03005281 }
5282
Arik Nemtsov72b06242011-12-07 21:21:51 +02005283 BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
5284
Luciano Coelhoe87288f2011-12-05 16:12:54 +02005285 /* adjust some runtime configuration parameters */
5286 wlcore_adjust_conf(wl);
5287
Felipe Balbia390e852011-10-06 10:07:44 +03005288 wl->irq = platform_get_irq(pdev, 0);
Felipe Balbia390e852011-10-06 10:07:44 +03005289 wl->platform_quirks = pdata->platform_quirks;
5290 wl->set_power = pdata->set_power;
5291 wl->dev = &pdev->dev;
5292 wl->if_ops = pdata->ops;
5293
5294 platform_set_drvdata(pdev, wl);
5295
5296 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5297 irqflags = IRQF_TRIGGER_RISING;
5298 else
5299 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5300
5301 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5302 irqflags,
5303 pdev->name, wl);
5304 if (ret < 0) {
5305 wl1271_error("request_irq() failed: %d", ret);
5306 goto out_free_hw;
5307 }
5308
5309 ret = enable_irq_wake(wl->irq);
5310 if (!ret) {
5311 wl->irq_wake_enabled = true;
5312 device_init_wakeup(wl->dev, 1);
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02005313 if (pdata->pwr_in_suspend) {
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005314 wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
Eyal Shapirab95d7ce2012-03-14 06:32:10 +02005315 wl->hw->wiphy->wowlan.n_patterns =
5316 WL1271_MAX_RX_FILTERS;
5317 wl->hw->wiphy->wowlan.pattern_min_len = 1;
5318 wl->hw->wiphy->wowlan.pattern_max_len =
5319 WL1271_RX_FILTER_MAX_PATTERN_SIZE;
5320 }
Felipe Balbia390e852011-10-06 10:07:44 +03005321 }
5322 disable_irq(wl->irq);
5323
Luciano Coelho4afc37a2012-05-10 12:14:02 +03005324 ret = wl12xx_get_hw_info(wl);
5325 if (ret < 0) {
5326 wl1271_error("couldn't get hw info");
5327 goto out;
5328 }
5329
5330 ret = wl->ops->identify_chip(wl);
5331 if (ret < 0)
5332 goto out;
5333
Felipe Balbia390e852011-10-06 10:07:44 +03005334 ret = wl1271_init_ieee80211(wl);
5335 if (ret)
5336 goto out_irq;
5337
5338 ret = wl1271_register_hw(wl);
5339 if (ret)
5340 goto out_irq;
5341
Felipe Balbif79f8902011-10-06 13:05:25 +03005342 /* Create sysfs file to control bt coex state */
5343 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5344 if (ret < 0) {
5345 wl1271_error("failed to create sysfs file bt_coex_state");
5346 goto out_irq;
5347 }
5348
5349 /* Create sysfs file to get HW PG version */
5350 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5351 if (ret < 0) {
5352 wl1271_error("failed to create sysfs file hw_pg_ver");
5353 goto out_bt_coex_state;
5354 }
5355
5356 /* Create sysfs file for the FW log */
5357 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5358 if (ret < 0) {
5359 wl1271_error("failed to create sysfs file fwlog");
5360 goto out_hw_pg_ver;
5361 }
5362
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005363 goto out;
Felipe Balbia390e852011-10-06 10:07:44 +03005364
Felipe Balbif79f8902011-10-06 13:05:25 +03005365out_hw_pg_ver:
5366 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5367
5368out_bt_coex_state:
5369 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5370
Felipe Balbia390e852011-10-06 10:07:44 +03005371out_irq:
5372 free_irq(wl->irq, wl);
5373
5374out_free_hw:
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005375 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03005376
5377out:
5378 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005379}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005380EXPORT_SYMBOL_GPL(wlcore_probe);
Felipe Balbice2a2172011-10-05 14:12:55 +03005381
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005382int __devexit wlcore_remove(struct platform_device *pdev)
Felipe Balbice2a2172011-10-05 14:12:55 +03005383{
Felipe Balbia390e852011-10-06 10:07:44 +03005384 struct wl1271 *wl = platform_get_drvdata(pdev);
5385
5386 if (wl->irq_wake_enabled) {
5387 device_init_wakeup(wl->dev, 0);
5388 disable_irq_wake(wl->irq);
5389 }
5390 wl1271_unregister_hw(wl);
5391 free_irq(wl->irq, wl);
Luciano Coelhoffeb5012011-11-21 18:55:51 +02005392 wlcore_free_hw(wl);
Felipe Balbia390e852011-10-06 10:07:44 +03005393
Felipe Balbice2a2172011-10-05 14:12:55 +03005394 return 0;
5395}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02005396EXPORT_SYMBOL_GPL(wlcore_remove);
Felipe Balbice2a2172011-10-05 14:12:55 +03005397
Guy Eilam491bbd62011-01-12 10:33:29 +01005398u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005399EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005400module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005401MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5402
Ido Yariv95dac04f2011-06-06 14:57:06 +03005403module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005404MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005405 "FW logger options: continuous, ondemand, dbgpins or disable");
5406
Eliad Peller2a5bff02011-08-25 18:10:59 +03005407module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5408MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5409
Arik Nemtsov34785be2011-12-08 13:06:45 +02005410module_param(no_recovery, bool, S_IRUSR | S_IWUSR);
5411MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
5412
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005413MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005414MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005415MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");