iwl-scan.c revision 759ef89fb096c4a6ef078d3cfd5682ac037bd789
12a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/******************************************************************************
22a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
32a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * GPL LICENSE SUMMARY
42a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
52a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Copyright(c) 2008 Intel Corporation. All rights reserved.
62a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
72a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * This program is free software; you can redistribute it and/or modify
82a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * it under the terms of version 2 of the GNU General Public License as
92a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * published by the Free Software Foundation.
102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * This program is distributed in the hope that it will be useful, but
122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * WITHOUT ANY WARRANTY; without even the implied warranty of
132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * General Public License for more details.
152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * You should have received a copy of the GNU General Public License
172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * along with this program; if not, write to the Free Software
182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * USA
202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * The full GNU General Public License is included in this distribution
222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * in the file called LICENSE.GPL.
232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Contact Information:
25759ef89fb096c4a6ef078d3cfd5682ac037bd789Winkler, Tomas *  Intel Linux Wireless <ilw@linux.intel.com>
262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *****************************************************************************/
287e272fcff6f0a32a3d46e600ea5895f6058f4e2dJohn W. Linville#include <linux/types.h>
292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include <linux/etherdevice.h>
307e272fcff6f0a32a3d46e600ea5895f6058f4e2dJohn W. Linville#include <net/lib80211.h>
317e272fcff6f0a32a3d46e600ea5895f6058f4e2dJohn W. Linville#include <net/mac80211.h>
322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-eeprom.h"
342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-dev.h"
352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-core.h"
362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-sta.h"
372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-io.h"
382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-helpers.h"
392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * sending probe req.  This should be set long enough to hear probe responses
422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * from more than one AP.  */
43fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
44fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_ACTIVE_DWELL_TIME_52    (20)
45fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler
46fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
47fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For faster active scanning, scan will move to the next channel if fewer than
502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * PLCP_QUIET_THRESH packets are heard on this channel within
512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * time if it's a quiet channel (nothing responded to our probe, and there's
532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * no other traffic).
542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)  /* packets */
56fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(10)  /* msec */
572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Must be set longer than active dwell time.
602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * For the most reliable scan, set > AP beacon interval (typically 100msec). */
612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_52   (10)
632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_BASE      (100)
642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_CHANNEL_TUNE_TIME       5
652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
66fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler#define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
67fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler
68fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler
692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/**
702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_scan_cancel - Cancel any currently executing HW scan
712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * NOTE: priv->mutex is not required before calling this function
732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */
742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_cancel(struct iwl_priv *priv)
752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCANNING, &priv->status);
782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCANNING, &priv->status)) {
822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			IWL_DEBUG_SCAN("Queuing scan abort.\n");
842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			set_bit(STATUS_SCAN_ABORTING, &priv->status);
852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			queue_work(priv->workqueue, &priv->abort_scan);
862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		} else
882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return test_bit(STATUS_SCANNING, &priv->status);
912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return 0;
942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
952a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_cancel);
962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/**
972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * @ms: amount of time to wait (in milliseconds) for scan to abort
992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
1002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * NOTE: priv->mutex must be held before calling this function
1012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */
1022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
1032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
1042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	unsigned long now = jiffies;
1052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	int ret;
1062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ret = iwl_scan_cancel(priv);
1082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (ret && ms) {
1092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		mutex_unlock(&priv->mutex);
1102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
1112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				test_bit(STATUS_SCANNING, &priv->status))
1122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			msleep(1);
1132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		mutex_lock(&priv->mutex);
1142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return test_bit(STATUS_SCANNING, &priv->status);
1162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
1172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return ret;
1192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
1202a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_cancel_timeout);
1212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic int iwl_send_scan_abort(struct iwl_priv *priv)
1232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
1242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	int ret = 0;
1252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_rx_packet *res;
1262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_host_cmd cmd = {
1272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		.id = REPLY_SCAN_ABORT_CMD,
1282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		.meta.flags = CMD_WANT_SKB,
1292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	};
1302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* If there isn't a scan actively going on in the hardware
1322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * then we are in between scan bands and not actually
1332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * actively scanning, so don't send the abort command */
1342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
1352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
1362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
1372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
1382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ret = iwl_send_cmd_sync(priv, &cmd);
1402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (ret) {
1412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
1422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return ret;
1432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
1442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
1462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (res->u.status != CAN_ABORT_STATUS) {
1472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		/* The scan abort will return 1 for success or
1482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * 2 for "failure".  A failure condition can be
1492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * due to simply not being in an active scan which
1502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * can occur if we send the scan abort before we
1512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * the microcode has notified us that a scan is
1522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * completed. */
1532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
1542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
1552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCAN_HW, &priv->status);
1562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
1572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
15814652562364dad636ddce2cd11e71702ca21bfbdEmmanuel Grumbach	priv->alloc_rxb_skb--;
1592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	dev_kfree_skb_any(cmd.meta.u.skb);
1602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return ret;
1622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
1632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service response to REPLY_SCAN_CMD (0x80) */
1662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_reply_scan(struct iwl_priv *priv,
1672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			      struct iwl_rx_mem_buffer *rxb)
1682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
1692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG
1702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
1712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_scanreq_notification *notif =
1722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    (struct iwl_scanreq_notification *)pkt->u.raw;
1732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
1752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif
1762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
1772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_START_NOTIFICATION (0x82) */
1792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_start_notif(struct iwl_priv *priv,
1802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				    struct iwl_rx_mem_buffer *rxb)
1812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
1822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
1832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_scanstart_notification *notif =
1842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    (struct iwl_scanstart_notification *)pkt->u.raw;
1852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
1862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_SCAN("Scan start: "
1872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       "%d [802.11%s] "
1882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
1892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       notif->channel,
1902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       notif->band ? "bg" : "a",
191fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		       le32_to_cpu(notif->tsf_high),
192fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		       le32_to_cpu(notif->tsf_low),
193fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		       notif->status, notif->beacon_timer);
1942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
1952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
1962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
1972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_results_notif(struct iwl_priv *priv,
1982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				      struct iwl_rx_mem_buffer *rxb)
1992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
2002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG
2012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
2022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_scanresults_notification *notif =
2032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    (struct iwl_scanresults_notification *)pkt->u.raw;
2042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_SCAN("Scan ch.res: "
2062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       "%d [802.11%s] "
2072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       "(TSF: 0x%08X:%08X) - %d "
2082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       "elapsed=%lu usec (%dms since last)\n",
2092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       notif->channel,
2102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       notif->band ? "bg" : "a",
2112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       le32_to_cpu(notif->tsf_high),
2122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       le32_to_cpu(notif->tsf_low),
2132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       le32_to_cpu(notif->statistics[0]),
2142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
2152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       jiffies_to_msecs(elapsed_jiffies
2162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler					(priv->last_scan_jiffies, jiffies)));
2172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif
2182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->last_scan_jiffies = jiffies;
2202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->next_scan_jiffies = 0;
2212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
2222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
2242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
2252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				       struct iwl_rx_mem_buffer *rxb)
2262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
227cb9289cb798502a5010c8f1d8d003842cd1449a4Denis V. Lunev#ifdef CONFIG_IWLWIFI_DEBUG
2282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
2292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
2302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
2322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       scan_notif->scanned_channels,
2332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       scan_notif->tsf_low,
2342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       scan_notif->tsf_high, scan_notif->status);
235cb9289cb798502a5010c8f1d8d003842cd1449a4Denis V. Lunev#endif
2362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* The HW is no longer scanning */
2382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	clear_bit(STATUS_SCAN_HW, &priv->status);
2392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* The scan completion notification came in, so kill that timer... */
2412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	cancel_delayed_work(&priv->scan_check);
2422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
2441b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
2451b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller						"2.4" : "5.2",
2462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       jiffies_to_msecs(elapsed_jiffies
2472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler					(priv->scan_pass_start, jiffies)));
2482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2491b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	/* Remove this scanned band from the list of pending
2501b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	 * bands to scan, band G precedes A in order of scanning
2511b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	 * as seen in iwl_bg_request_scan */
2521b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
2531b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
2541b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
2551b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
2562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* If a request to abort was given, or the scan did not succeed
2582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * then we reset the scan state machine and terminate,
2592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * re-queuing another scan if one has been requested */
2602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
2612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_INFO("Aborted scan completed.\n");
2622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
2632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	} else {
2642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		/* If there are more bands on this scan pass reschedule */
2651b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		if (priv->scan_bands)
2662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			goto reschedule;
2672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
2682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->last_scan_jiffies = jiffies;
2702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->next_scan_jiffies = 0;
2712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_INFO("Setting scan to off\n");
2722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	clear_bit(STATUS_SCANNING, &priv->status);
2742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_INFO("Scan took %dms\n",
2762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
2772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	queue_work(priv->workqueue, &priv->scan_completed);
2792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return;
2812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerreschedule:
2832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->scan_pass_start = jiffies;
2842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	queue_work(priv->workqueue, &priv->request_scan);
2852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
2862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
2882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
2892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* scan handlers */
2902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
2912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
2922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
2932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler					iwl_rx_scan_results_notif;
2942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
2952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler					iwl_rx_scan_complete_notif;
2962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
2972a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
2982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
2992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
300fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler					    enum ieee80211_band band,
301fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler					    u8 n_probes)
3022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
3032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (band == IEEE80211_BAND_5GHZ)
304fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		return IWL_ACTIVE_DWELL_TIME_52 +
305fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
3062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	else
307fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		return IWL_ACTIVE_DWELL_TIME_24 +
308fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
3092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
3102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
312fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler				      enum ieee80211_band band)
3132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
314fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
3152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
3162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
3172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (iwl_is_associated(priv)) {
3192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		/* If we're associated, we clamp the maximum passive
3202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * dwell time to be 98% of the beacon interval (minus
3212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		 * 2 * channel tune time) */
3222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		passive = priv->beacon_int;
3232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
3242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			passive = IWL_PASSIVE_DWELL_BASE;
3252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
3262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
3272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return passive;
3292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
3302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic int iwl_get_channels_for_scan(struct iwl_priv *priv,
3322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				     enum ieee80211_band band,
333fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler				     u8 is_active, u8 n_probes,
3342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				     struct iwl_scan_channel *scan_ch)
3352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
3362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	const struct ieee80211_channel *channels = NULL;
3372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	const struct ieee80211_supported_band *sband;
3382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	const struct iwl_channel_info *ch_info;
3392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u16 passive_dwell = 0;
3402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u16 active_dwell = 0;
3412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	int added, i;
342d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler	u16 channel;
3432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	sband = iwl_get_hw_mode(priv, band);
3452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!sband)
3462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
3472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	channels = sband->channels;
3492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
350fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler	active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
3512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	passive_dwell = iwl_get_passive_dwell_time(priv, band);
3522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
353fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler	if (passive_dwell <= active_dwell)
354fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		passive_dwell = active_dwell + 1;
355fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler
3562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	for (i = 0, added = 0; i < sband->n_channels; i++) {
3572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (channels[i].flags & IEEE80211_CHAN_DISABLED)
3582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			continue;
3592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
360d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler		channel =
3612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			ieee80211_frequency_to_channel(channels[i].center_freq);
362d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler		scan_ch->channel = cpu_to_le16(channel);
3632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
364d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler		ch_info = iwl_get_channel_info(priv, band, channel);
3652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!is_channel_valid(ch_info)) {
3661b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
367d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler					channel);
3682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			continue;
3692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		}
3702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!is_active || is_channel_passive(ch_info) ||
3722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
373d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
3742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		else
375d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler			scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
3762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3770ffe014a8c548f88694815ae7b25d6e86550917eRon Rindjunsky		if (n_probes)
378fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
3792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan_ch->active_dwell = cpu_to_le16(active_dwell);
3812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
3822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
3832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		/* Set txpower levels to defaults */
384f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		scan_ch->dsp_atten = 110;
3852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
386fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		/* NOTE: if we were doing 6Mb OFDM for scans we'd use
387fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		 * power level:
388fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
389fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		 */
3902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (band == IEEE80211_BAND_5GHZ)
391f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
392fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		else
393f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
3942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
395fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n",
396fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			       channel, le32_to_cpu(scan_ch->type),
397d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
398d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler				"ACTIVE" : "PASSIVE",
399d16dc48a2ea14af9980d0ea79d041f4b53e47b62Tomas Winkler			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
4002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			       active_dwell : passive_dwell);
4012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan_ch++;
4032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		added++;
4042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
4072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return added;
4082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
4092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
410f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winklervoid iwl_init_scan_params(struct iwl_priv *priv)
411f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler{
41276eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
413f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
41476eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
415f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
41676eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
417f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler}
418f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
4192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_initiate(struct iwl_priv *priv)
4202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
4212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!iwl_is_ready_rf(priv)) {
4222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
4232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return -EIO;
4242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCANNING, &priv->status)) {
4272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_SCAN("Scan already in progress.\n");
4282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return -EAGAIN;
4292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
4328d09a5e1c36d0dec5728e6c8b0bb5412de09b27bTomas Winkler		IWL_DEBUG_SCAN("Scan request while abort pending\n");
4332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return -EAGAIN;
4342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	IWL_DEBUG_INFO("Starting scan...\n");
4371b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	if (priv->cfg->sku & IWL_SKU_G)
4381b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
4391b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	if (priv->cfg->sku & IWL_SKU_A)
4401b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
4412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	set_bit(STATUS_SCANNING, &priv->status);
4422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->scan_start = jiffies;
4432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	priv->scan_pass_start = priv->scan_start;
4442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	queue_work(priv->workqueue, &priv->request_scan);
4462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return 0;
4482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
4492a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_initiate);
4502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
4522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_scan_check(struct work_struct *data)
4542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
4552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_priv *priv =
4562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    container_of(data, struct iwl_priv, scan_check.work);
4572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
4592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return;
4602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_lock(&priv->mutex);
4622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCANNING, &priv->status) ||
4632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
4642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting "
4652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			"adapter (%dms)\n",
4662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
4672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
4692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			iwl_send_scan_abort(priv);
4702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_unlock(&priv->mutex);
4722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
4732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/**
4742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_supported_rate_to_ie - fill in the supported rate in IE field
4752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *
4762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * return : set the bit for each supported rate insert in ie
4772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */
4782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
4792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				    u16 basic_rate, int *left)
4802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
4812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u16 ret_rates = 0, bit;
4822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	int i;
4832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u8 *cnt = ie;
4842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u8 *rates = ie + 1;
4852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
4872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (bit & supported_rate) {
4882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			ret_rates |= bit;
4892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			rates[*cnt] = iwl_rates[i].ieee |
4902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				((bit & basic_rate) ? 0x80 : 0x00);
4912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			(*cnt)++;
4922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			(*left)--;
4932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			if ((*left <= 0) ||
4942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			    (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
4952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				break;
4962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		}
4972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
4982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
4992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return ret_rates;
5002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
5012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
504f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler			     u8 *pos, int *left)
5052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
5062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct ieee80211_ht_cap *ht_cap;
5072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
508d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg	if (!sband || !sband->ht_cap.ht_supported)
5092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return;
5102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (*left < sizeof(struct ieee80211_ht_cap))
5122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return;
5132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = sizeof(struct ieee80211_ht_cap);
5152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ht_cap = (struct ieee80211_ht_cap *) pos;
5162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
517d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg	ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
518d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg	memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16);
5192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ht_cap->ampdu_params_info =
520d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg		(sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) |
521d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg		((sband->ht_cap.ampdu_density << 2) &
522d9fe60dea7779d412b34679f1177c5ca1940ea8dJohannes Berg			IEEE80211_HT_AMPDU_PARM_DENSITY);
5232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*left -= sizeof(struct ieee80211_ht_cap);
5242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
5252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/**
5272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_fill_probe_req - fill in all required fields and IE for probe request
5282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */
529f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
5302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_fill_probe_req(struct iwl_priv *priv,
5312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				  enum ieee80211_band band,
5322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				  struct ieee80211_mgmt *frame,
533f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				  int left)
5342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
5352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	int len = 0;
5362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u8 *pos = NULL;
5372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u16 active_rates, ret_rates, cck_rates, active_rate_basic;
5382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	const struct ieee80211_supported_band *sband =
5392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler						iwl_get_hw_mode(priv, band);
5402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
541f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
5422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* Make sure there is enough space for the probe request,
5432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * two mandatory IEs and the data */
5442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	left -= 24;
5452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (left < 0)
5462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
5472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
5492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
5502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
5512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
5522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	frame->seq_ctrl = 0;
5532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
554f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	len += 24;
555f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
5562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* ...next IE... */
557f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	pos = &frame->u.probe_req.variable[0];
5582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
559f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	/* fill in our indirect SSID IE */
5602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	left -= 2;
5612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (left < 0)
5622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
5632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = WLAN_EID_SSID;
5642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = 0;
5652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
566f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	len += 2;
5672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* fill in supported rate */
5692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	left -= 2;
5702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (left < 0)
5712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
5722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = WLAN_EID_SUPP_RATES;
5742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos = 0;
5752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* exclude 60M rate */
5772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	active_rates = priv->rates_mask;
5782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	active_rates &= ~IWL_RATE_60M_MASK;
5792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	active_rate_basic = active_rates & IWL_BASIC_RATES_MASK;
5812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	cck_rates = IWL_CCK_RATES_MASK & active_rates;
5832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
584f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler					     active_rate_basic, &left);
5852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	active_rates &= ~ret_rates;
5862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
588f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler					     active_rate_basic, &left);
5892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	active_rates &= ~ret_rates;
5902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	len += 2 + *pos;
5922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	pos += (*pos) + 1;
593f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
5942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (active_rates == 0)
5952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto fill_end;
5962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
5972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* fill in supported extended rate */
5982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* ...next IE... */
5992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	left -= 2;
6002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (left < 0)
6012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
6022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* ... fill it in... */
6032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = WLAN_EID_EXT_SUPP_RATES;
6042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos = 0;
605f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left);
606f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	if (*pos > 0) {
6072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		len += 2 + *pos;
608f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		pos += (*pos) + 1;
609f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	} else {
610f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		pos--;
611f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	}
6122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler fill_end:
614f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
6152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	left -= 2;
6162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (left < 0)
6172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return 0;
6182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos++ = WLAN_EID_HT_CAPABILITY;
6202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	*pos = 0;
6212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	iwl_ht_cap_to_ie(sband, pos, &left);
6222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (*pos > 0)
6232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		len += 2 + *pos;
624f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
6252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return (u16)len;
6262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
6272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_request_scan(struct work_struct *data)
6292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
6302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_priv *priv =
6312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    container_of(data, struct iwl_priv, request_scan);
6322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_host_cmd cmd = {
6332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		.id = REPLY_SCAN_CMD,
6342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		.len = sizeof(struct iwl_scan_cmd),
6352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		.meta.flags = CMD_SIZE_HUGE,
6362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	};
6372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_scan_cmd *scan;
6382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct ieee80211_conf *conf = NULL;
639f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	int ret = 0;
64076eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	u32 rate_flags = 0;
6412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	u16 cmd_len;
6422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	enum ieee80211_band band;
643fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler	u8 n_probes = 2;
644d588be6bae40f7965f1b681a4dbc3254411787b9Tomas Winkler	u8 rx_chain = priv->hw_params.valid_rx_ant;
64576eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	u8 rate;
6469387b7caf3049168fc97a8a9111af8fe2143af18John W. Linville	DECLARE_SSID_BUF(ssid);
6472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	conf = ieee80211_get_hw_conf(priv->hw);
6492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_lock(&priv->mutex);
6512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!iwl_is_ready(priv)) {
6532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_WARNING("request scan called when driver not ready.\n");
6542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
657a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler	/* Make sure the scan wasn't canceled before this queued work
6582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * was given the chance to run... */
6592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!test_bit(STATUS_SCANNING, &priv->status))
6602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* This should never be called or scheduled if there is currently
6632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	 * a scan active in the hardware. */
6642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
6652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
6662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			       "Ignoring second request.\n");
6672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		ret = -EIO;
6682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
6722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
6732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
6772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
6782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (iwl_is_rfkill(priv)) {
6822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
6832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!test_bit(STATUS_READY, &priv->status)) {
6872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
6882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!priv->scan_bands) {
6922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
6932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
6942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
6952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
6962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!priv->scan) {
6972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
6982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
6992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!priv->scan) {
7002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			ret = -ENOMEM;
7012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			goto done;
7022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		}
7032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
7042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan = priv->scan;
7052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
7062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
7082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
7092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (iwl_is_associated(priv)) {
7112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		u16 interval = 0;
7122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		u32 extra;
7132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		u32 suspend_time = 100;
7142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		u32 scan_suspend_time = 100;
7152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		unsigned long flags;
7162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_INFO("Scanning while associated...\n");
7182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		spin_lock_irqsave(&priv->lock, flags);
7202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		interval = priv->beacon_int;
7212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		spin_unlock_irqrestore(&priv->lock, flags);
7222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->suspend_time = 0;
7242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->max_out_time = cpu_to_le32(200 * 1024);
7252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		if (!interval)
7262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			interval = suspend_time;
7272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		extra = (suspend_time / interval) << 22;
7292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan_suspend_time = (extra |
7302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		    ((suspend_time % interval) * 1024));
7312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->suspend_time = cpu_to_le32(scan_suspend_time);
7322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
7332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			       scan_suspend_time, interval);
7342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
7352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* We should add the ability for user to lock to PASSIVE ONLY */
7372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (priv->one_direct_scan) {
738f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		IWL_DEBUG_SCAN("Start direct scan for '%s'\n",
7399387b7caf3049168fc97a8a9111af8fe2143af18John W. Linville				print_ssid(ssid, priv->direct_ssid,
7409387b7caf3049168fc97a8a9111af8fe2143af18John W. Linville					   priv->direct_ssid_len));
7412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->direct_scan[0].id = WLAN_EID_SSID;
7422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->direct_scan[0].len = priv->direct_ssid_len;
7432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		memcpy(scan->direct_scan[0].ssid,
7442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		       priv->direct_ssid, priv->direct_ssid_len);
745fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		n_probes++;
7462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	} else {
747f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		IWL_DEBUG_SCAN("Start indirect scan.\n");
7482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
7492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
7512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
7522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
7532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7551b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
756f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		band = IEEE80211_BAND_2GHZ;
7572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
75876eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) {
75976eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler			rate = IWL_RATE_6M_PLCP;
76076eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		} else {
76176eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler			rate = IWL_RATE_1M_PLCP;
76276eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler			rate_flags = RATE_MCS_CCK_MSK;
76376eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		}
7642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->good_CRC_th = 0;
7651b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
766f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		band = IEEE80211_BAND_5GHZ;
76776eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler		rate = IWL_RATE_6M_PLCP;
7682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->good_CRC_th = IWL_GOOD_CRC_TH;
7692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
770f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		/* Force use of chains B and C (0x6) for scan Rx for 4965
771f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		 * Avoid A (0x1) because of its off-channel reception on A-band.
7725118303f7cc0520ce2969ea3d890dc05d586ceb2Tomas Winkler		 */
773f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
774f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler			rx_chain = 0x6;
7751b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller	} else {
7762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		IWL_WARNING("Invalid scan band count\n");
7772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
7782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	}
7792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
78076eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	priv->scan_tx_ant[band] =
78176eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler			 iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
78276eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
78376eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler	scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
78476eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler
7855118303f7cc0520ce2969ea3d890dc05d586ceb2Tomas Winkler	/* MIMO is not used here, but value is required */
786f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
787f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
788f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				(rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) |
789f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				(0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
790f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
7912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	cmd_len = iwl_fill_probe_req(priv, band,
792f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				     (struct ieee80211_mgmt *)scan->data,
793f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler				     IWL_MAX_SCAN_SIZE - sizeof(*scan));
7942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
7952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->tx_cmd.len = cpu_to_le16(cmd_len);
7962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
79705c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
7982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		scan->filter_flags = RXON_FILTER_PROMISC_MSK;
7992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
800f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
801f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler			       RXON_FILTER_BCON_AWARE_MSK);
802f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler
803fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler	scan->channel_count =
804fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler		iwl_get_channels_for_scan(priv, band, 1, /* active */
805fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			n_probes,
806fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
807fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler
808f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	if (scan->channel_count == 0) {
809f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
810f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler		goto done;
811f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler	}
8122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
8142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	    scan->channel_count * sizeof(struct iwl_scan_channel);
8152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	cmd.data = scan;
8162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	scan->len = cpu_to_le16(cmd.len);
8172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	set_bit(STATUS_SCAN_HW, &priv->status);
8192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	ret = iwl_send_cmd_sync(priv, &cmd);
8202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (ret)
8212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		goto done;
8222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	queue_delayed_work(priv->workqueue, &priv->scan_check,
8242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler			   IWL_SCAN_CHECK_WATCHDOG);
8252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_unlock(&priv->mutex);
8272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	return;
8282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler done:
830951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	/* Cannot perform scan. Make sure we clear scanning
831951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	* bits from status so next scan request can be performed.
832951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	* If we don't clear scanning status bit here all next scan
833951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	* will fail
834951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	*/
835951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	clear_bit(STATUS_SCAN_HW, &priv->status);
836951891c7ef844919d30aac7b1fc7396fd8be23ffMohamed Abbas	clear_bit(STATUS_SCANNING, &priv->status);
8372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	/* inform mac80211 scan aborted */
8382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	queue_work(priv->workqueue, &priv->scan_completed);
8392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_unlock(&priv->mutex);
8402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
8412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_abort_scan(struct work_struct *work)
8432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
8442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
8452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	if (!iwl_is_ready(priv))
8472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler		return;
8482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_lock(&priv->mutex);
8502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	set_bit(STATUS_SCAN_ABORTING, &priv->status);
8522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	iwl_send_scan_abort(priv);
8532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
8542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	mutex_unlock(&priv->mutex);
8552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
8562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
857eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winklerstatic void iwl_bg_scan_completed(struct work_struct *work)
858eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler{
859eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	struct iwl_priv *priv =
860eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	    container_of(work, struct iwl_priv, scan_completed);
861eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
862eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	IWL_DEBUG_SCAN("SCAN complete scan\n");
863eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
864eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
865eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler		return;
866eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
867eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	ieee80211_scan_completed(priv->hw);
868eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
869eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	/* Since setting the TXPOWER may have been deferred while
870eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	 * performing the scan, fire one off */
871eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	mutex_lock(&priv->mutex);
872eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
873eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	mutex_unlock(&priv->mutex);
874eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler}
875eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
876eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler
8772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_scan_deferred_work(struct iwl_priv *priv)
8782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{
879eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
8802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
8812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
8822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
8832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler}
8842a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_setup_scan_deferred_work);
8852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler
886