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