12a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/****************************************************************************** 22a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 32a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * GPL LICENSE SUMMARY 42a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 5fb4961dbc27d40cdbed297aa9bd74fa4a0e2ba6cWey-Yi Guy * Copyright(c) 2008 - 2012 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 *****************************************************************************/ 285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 297e272fcff6f0a32a3d46e600ea5895f6058f4e2dJohn W. Linville#include <linux/types.h> 302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include <linux/etherdevice.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-io.h" 37e80d70e98b993a7ece93e29a408da4a7d57a4da2Wey-Yi Guy#include "iwl-agn.h" 38bdfbf0924ab05e02d28e50bd2d5024097642a78dEmmanuel Grumbach#include "iwl-trans.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 passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. 502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Must be set longer than active dwell time. 512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * For the most reliable scan, set > AP beacon interval (typically 100msec). */ 522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ 532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_52 (10) 542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_BASE (100) 552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_CHANNEL_TUNE_TIME 5 562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 57cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszkastatic int iwl_send_scan_abort(struct iwl_priv *priv) 58cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka{ 59cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka int ret; 60cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka struct iwl_host_cmd cmd = { 61cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka .id = REPLY_SCAN_ABORT_CMD, 62e419d62d72b23392e7f9a5da047fb17d70edc54aEmmanuel Grumbach .flags = CMD_SYNC | CMD_WANT_SKB, 63cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka }; 64f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg __le32 *status; 65fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler 66cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka /* Exit instantly with error when device is not ready 67cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * to receive scan abort command or it does not perform 68cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * hardware scan currently */ 6983626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_READY, &priv->status) || 7083626404a70da74c67f32f119e53c0ba032ba2d8Don Fry !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || 7183626404a70da74c67f32f119e53c0ba032ba2d8Don Fry !test_bit(STATUS_SCAN_HW, &priv->status) || 725c40d8603d8ed03aa851d20ad8a9155fc79a1b07Johannes Berg test_bit(STATUS_FW_ERROR, &priv->shrd->status)) 73cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka return -EIO; 74fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler 75e10a0533a9172471b52bd9512838d766420a3bafJohannes Berg ret = iwl_dvm_send_cmd(priv, &cmd); 76cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka if (ret) 77cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka return ret; 78cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka 79f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg status = (void *)cmd.resp_pkt->data; 80f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg if (*status != CAN_ABORT_STATUS) { 81cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka /* The scan abort will return 1 for success or 82cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * 2 for "failure". A failure condition can be 83cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * due to simply not being in an active scan which 84cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * can occur if we send the scan abort before we 85cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * the microcode has notified us that a scan is 86cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * completed. */ 87f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", 88f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg le32_to_cpu(*status)); 89cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka ret = -EIO; 902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9265b94a4abfd55b3304be25ffed9832455d41e1ddJohannes Berg iwl_free_resp(&cmd); 93cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka return ret; 94cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka} 952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9602d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszkastatic void iwl_complete_scan(struct iwl_priv *priv, bool aborted) 9702d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka{ 9802d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka /* check if scan was requested from mac80211 */ 9902d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka if (priv->scan_request) { 10002d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); 10102d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka ieee80211_scan_completed(priv->hw, aborted); 10202d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka } 10302d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka 104c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg if (priv->scan_type == IWL_SCAN_ROC) { 105c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg ieee80211_remain_on_channel_expired(priv->hw); 106c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg priv->hw_roc_channel = NULL; 107c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); 108c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg } 109c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg 110266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg priv->scan_type = IWL_SCAN_NORMAL; 11102d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka priv->scan_vif = NULL; 11202d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka priv->scan_request = NULL; 11302d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka} 11402d8c14b590f583fd6e8c16fe779f845845effd9Stanislaw Gruszka 115a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Bergstatic void iwl_process_scan_complete(struct iwl_priv *priv) 116a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg{ 117a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg bool aborted; 118a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 119b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 12084b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg 12183626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status)) 12284b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg return; 12384b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg 124a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg IWL_DEBUG_SCAN(priv, "Completed scan.\n"); 125a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 126a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg cancel_delayed_work(&priv->scan_check); 127a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 12883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); 129a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg if (aborted) 130a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); 131a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 13283626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { 133a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); 134a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg goto out_settings; 135a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg } 136a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 137a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg if (priv->scan_type == IWL_SCAN_ROC) { 138a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg ieee80211_remain_on_channel_expired(priv->hw); 139a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg priv->hw_roc_channel = NULL; 140a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); 141a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg } 142a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 143a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { 144a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg int err; 145a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 146a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg /* Check if mac80211 requested scan during our internal scan */ 147a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg if (priv->scan_request == NULL) 148a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg goto out_complete; 149a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 150a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg /* If so request a new scan */ 151a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, 152a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg priv->scan_request->channels[0]->band); 153a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg if (err) { 154a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg IWL_DEBUG_SCAN(priv, 155a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg "failed to initiate pending scan: %d\n", err); 156a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg aborted = true; 157a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg goto out_complete; 158a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg } 159a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 160a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg return; 161a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg } 162a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 163a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Bergout_complete: 164a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg iwl_complete_scan(priv, aborted); 165a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 166a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Bergout_settings: 167a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg /* Can we still talk to firmware ? */ 16883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!iwl_is_ready_rf(priv)) 169a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg return; 170a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 171a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg iwlagn_post_scan(priv); 172a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg} 173a2fa2462f05115722beb2443d081a72f4f4450eaJohannes Berg 174e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszkavoid iwl_force_scan_end(struct iwl_priv *priv) 175f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka{ 176b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 177e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka 17883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_SCANNING, &priv->status)) { 179e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); 180e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka return; 181e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka } 182e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka 183f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); 18483626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCANNING, &priv->status); 18583626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCAN_HW, &priv->status); 18683626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCAN_ABORTING, &priv->status); 18783626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCAN_COMPLETE, &priv->status); 188f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka iwl_complete_scan(priv, true); 189f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka} 190f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka 191cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszkastatic void iwl_do_scan_abort(struct iwl_priv *priv) 192cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka{ 193cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka int ret; 1942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 195b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 196cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka 19783626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_SCANNING, &priv->status)) { 198cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n"); 199cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka return; 2002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 2012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 20283626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) { 203cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan abort in progress\n"); 204cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka return; 205cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka } 206cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka 207cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka ret = iwl_send_scan_abort(priv); 208cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka if (ret) { 209cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); 210f5354c17dc29681c241f2774f3ef9478fb586673Stanislaw Gruszka iwl_force_scan_end(priv); 211cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka } else 21225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); 213cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka} 214cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka 215cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka/** 216cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka * iwl_scan_cancel - Cancel any currently executing HW scan 217cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka */ 218cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszkaint iwl_scan_cancel(struct iwl_priv *priv) 219cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka{ 220cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); 2211ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_work(priv->workqueue, &priv->abort_scan); 2222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 2232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 224cd44600fdd89832c0bc898189270a81be0db01cdStanislaw Gruszka 2252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/** 2262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_scan_cancel_timeout - Cancel any currently executing HW scan 2272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * @ms: amount of time to wait (in milliseconds) for scan to abort 2282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 2292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 23098efb4a52b5c64c79647ea4fdb2c6a3f3db6e743Johannes Bergvoid iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) 2312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 232e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka unsigned long timeout = jiffies + msecs_to_jiffies(ms); 233e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka 234b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 2352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 236e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n"); 2372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 238e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka iwl_do_scan_abort(priv); 239e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka 240e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka while (time_before_eq(jiffies, timeout)) { 24183626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!test_bit(STATUS_SCAN_HW, &priv->status)) 24284b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg goto finished; 243e693a802f06f538b711333a32a83e2732dc4773dStanislaw Gruszka msleep(20); 2442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 24584b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg 24684b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg return; 24784b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg 24884b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg finished: 24984b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg /* 25084b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * Now STATUS_SCAN_HW is clear. This means that the 25184b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * device finished, but the background work is going 25284b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * to execute at best as soon as we release the mutex. 25384b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * Since we need to be able to issue a new scan right 25484b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * after this function returns, run the complete here. 25584b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * The STATUS_SCAN_COMPLETE bit will then be cleared 25684b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * and prevent the background work from "completing" 25784b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * a possible new scan. 25884b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg */ 25984b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg iwl_process_scan_complete(priv); 2602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service response to REPLY_SCAN_CMD (0x80) */ 263247c61d625154e18a105d663281c52376a882762Emmanuel Grumbachstatic int iwl_rx_reply_scan(struct iwl_priv *priv, 26448a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 265247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 2662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG 2682f301227a1ede57504694e1f64839839f5737cacZhu Yi struct iwl_rx_packet *pkt = rxb_addr(rxb); 269f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_scanreq_notification *notif = (void *)pkt->data; 2702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2717cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); 2722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif 273247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 2742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_START_NOTIFICATION (0x82) */ 277247c61d625154e18a105d663281c52376a882762Emmanuel Grumbachstatic int iwl_rx_scan_start_notif(struct iwl_priv *priv, 27848a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 279247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 2802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2812f301227a1ede57504694e1f64839839f5737cacZhu Yi struct iwl_rx_packet *pkt = rxb_addr(rxb); 282f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_scanstart_notification *notif = (void *)pkt->data; 283f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg 2842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); 285e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_SCAN(priv, "Scan start: " 2862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "%d [802.11%s] " 2872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", 2882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->channel, 2892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->band ? "bg" : "a", 290fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler le32_to_cpu(notif->tsf_high), 291fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler le32_to_cpu(notif->tsf_low), 292fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler notif->status, notif->beacon_timer); 293c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg 294390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg if (priv->scan_type == IWL_SCAN_ROC && 295390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg !priv->hw_roc_start_notified) { 296c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg ieee80211_ready_on_channel(priv->hw); 297390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg priv->hw_roc_start_notified = true; 298390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg } 299247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach 300247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 3012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ 304247c61d625154e18a105d663281c52376a882762Emmanuel Grumbachstatic int iwl_rx_scan_results_notif(struct iwl_priv *priv, 30548a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 306247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 3072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG 3092f301227a1ede57504694e1f64839839f5737cacZhu Yi struct iwl_rx_packet *pkt = rxb_addr(rxb); 310f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_scanresults_notification *notif = (void *)pkt->data; 3112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 312e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_SCAN(priv, "Scan ch.res: " 3132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "%d [802.11%s] " 3141895b36bfb6165feb8f0b2060114632e46798dfeWey-Yi Guy "probe status: %u:%u " 3152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "(TSF: 0x%08X:%08X) - %d " 316220575f78fb0b8d2a1c41cd28115d52ae8d132eeHenry Zhangh "elapsed=%lu usec\n", 3172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->channel, 3182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->band ? "bg" : "a", 3191895b36bfb6165feb8f0b2060114632e46798dfeWey-Yi Guy notif->probe_status, notif->num_probe_not_sent, 3202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->tsf_high), 3212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->tsf_low), 3222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->statistics[0]), 323220575f78fb0b8d2a1c41cd28115d52ae8d132eeHenry Zhangh le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); 3242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif 325247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 3262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ 329247c61d625154e18a105d663281c52376a882762Emmanuel Grumbachstatic int iwl_rx_scan_complete_notif(struct iwl_priv *priv, 33048a2d66f58d2bf1818acf5ff7ed9897a9977a96eJohannes Berg struct iwl_rx_cmd_buffer *rxb, 331247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach struct iwl_device_cmd *cmd) 3322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3332f301227a1ede57504694e1f64839839f5737cacZhu Yi struct iwl_rx_packet *pkt = rxb_addr(rxb); 334f8d7c1a18d5e77b17b5cc1ebefa21eaea7f2d0faJohannes Berg struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data; 3352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 336e1623446bb1de1834ff1c57b3e8ed341d5d4a927Tomas Winkler IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", 3372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->scanned_channels, 3382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->tsf_low, 3392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->tsf_high, scan_notif->status); 3402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3417cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", 34200700ee007cf842ef2eb20201080ceddcfdaf9adJohannes Berg (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", 343ef1b21f7eb074a8c8ddfea70ed70e988545c8d54Stanislaw Gruszka jiffies_to_msecs(jiffies - priv->scan_start)); 3442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 34584b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg /* 34684b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * When aborting, we run the scan completed background work inline 34784b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * and the background work must then do nothing. The SCAN_COMPLETE 34884b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * bit helps implement that logic and thus needs to be set before 34984b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * queueing the work. Also, since the scan abort waits for SCAN_HW 35084b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW 35184b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg * to avoid a race there. 35284b1bec6d716fc8c289e2530cab109a6e097455bJohannes Berg */ 35383626404a70da74c67f32f119e53c0ba032ba2d8Don Fry set_bit(STATUS_SCAN_COMPLETE, &priv->status); 35483626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCAN_HW, &priv->status); 3551ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_work(priv->workqueue, &priv->scan_completed); 3562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 357f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy if (priv->iw_mode != NL80211_IFTYPE_ADHOC && 35888e58fc5d940c3463c7070a2a7a8a0ce65af3fdcStanislaw Gruszka iwl_advanced_bt_coexist(priv) && 359d5926d9d6a183d109060f68c0b96ea2b33c15377Johannes Berg priv->bt_status != scan_notif->bt_status) { 360f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy if (scan_notif->bt_status) { 361f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy /* BT on */ 362f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy if (!priv->bt_ch_announce) 363f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy priv->bt_traffic_load = 364f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy IWL_BT_COEX_TRAFFIC_LOAD_HIGH; 365f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy /* 366f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy * otherwise, no traffic load information provided 367f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy * no changes made 368f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy */ 369f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy } else { 370f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy /* BT off */ 371f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy priv->bt_traffic_load = 372f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy IWL_BT_COEX_TRAFFIC_LOAD_NONE; 373f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy } 374f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy priv->bt_status = scan_notif->bt_status; 3751ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_work(priv->workqueue, 37674e28e44095e30ffd2d0258e4fe91826a15247e7Emmanuel Grumbach &priv->bt_traffic_change_work); 377f78e545449bb07a28b419d888c4c558b13d9e5e1Wey-Yi Guy } 378247c61d625154e18a105d663281c52376a882762Emmanuel Grumbach return 0; 3792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_rx_scan_handlers(struct iwl_priv *priv) 3822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* scan handlers */ 3842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; 3852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; 3862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = 3872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_rx_scan_results_notif; 3882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = 3892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_rx_scan_complete_notif; 3902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3926e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Bergstatic u16 iwl_get_active_dwell_time(struct iwl_priv *priv, 3936e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg enum ieee80211_band band, u8 n_probes) 3942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (band == IEEE80211_BAND_5GHZ) 396fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler return IWL_ACTIVE_DWELL_TIME_52 + 397fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); 3982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler else 399fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler return IWL_ACTIVE_DWELL_TIME_24 + 400fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); 4012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 4022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 403390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Bergstatic u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) 404390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg{ 405390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg struct iwl_rxon_context *ctx; 406390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 407390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg /* 408390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg * If we're associated, we clamp the dwell time 98% 409390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg * of the smallest beacon interval (minus 2 * channel 410390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg * tune time) 411390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg */ 412390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg for_each_context(priv, ctx) { 413390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg u16 value; 414390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 4152ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg switch (ctx->staging.dev_type) { 4162ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg case RXON_DEV_TYPE_P2P: 4172ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg /* no timing constraints */ 418eb32043f430d74d4381b29273d174b376593d072Johannes Berg continue; 4192ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg case RXON_DEV_TYPE_ESS: 4202ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg default: 4212ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg /* timing constraints if associated */ 4222ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg if (!iwl_is_associated_ctx(ctx)) 4232ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg continue; 4242ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg break; 4252ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg case RXON_DEV_TYPE_CP: 4262ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg case RXON_DEV_TYPE_2STA: 4272ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg /* 4282ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg * These seem to always have timers for TBTT 4292ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg * active in uCode even when not associated yet. 4302ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg */ 4312ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg break; 4322ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg } 4332ed81710ccc0ccebe177481b8d4ac584f9c2b569Johannes Berg 434390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg value = ctx->beacon_int; 435390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg if (!value) 436390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg value = IWL_PASSIVE_DWELL_BASE; 437390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; 438390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg dwell_time = min(value, dwell_time); 439390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg } 440390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 441390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg return dwell_time; 442390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg} 443390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 4446e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Bergstatic u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, 4456e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg enum ieee80211_band band) 4462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 447fe905f1d5a8404f45fa0df26e6a870bf1e3b5983Tomas Winkler u16 passive = (band == IEEE80211_BAND_2GHZ) ? 4482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : 4492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; 4502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 451390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg return iwl_limit_dwell(priv, passive); 4522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 4532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4546e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Bergstatic int iwl_get_single_channel_for_scan(struct iwl_priv *priv, 4556e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct ieee80211_vif *vif, 4566e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg enum ieee80211_band band, 4576e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_scan_channel *scan_ch) 4586e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg{ 4596e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg const struct ieee80211_supported_band *sband; 4606e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 passive_dwell = 0; 4616e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 active_dwell = 0; 4626e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg int added = 0; 4636e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 channel = 0; 4646e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 4656e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg sband = iwl_get_hw_mode(priv, band); 4666e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!sband) { 4676e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_ERR(priv, "invalid band\n"); 4686e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return added; 4696e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 4706e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 4716e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg active_dwell = iwl_get_active_dwell_time(priv, band, 0); 4726e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg passive_dwell = iwl_get_passive_dwell_time(priv, band); 4736e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 4746e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (passive_dwell <= active_dwell) 4756e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg passive_dwell = active_dwell + 1; 4766e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 4776e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg channel = iwl_get_single_channel_number(priv, band); 4786e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (channel) { 4796e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->channel = cpu_to_le16(channel); 4806e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; 4816e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->active_dwell = cpu_to_le16(active_dwell); 4826e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->passive_dwell = cpu_to_le16(passive_dwell); 4836e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* Set txpower levels to defaults */ 4846e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->dsp_atten = 110; 4856e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (band == IEEE80211_BAND_5GHZ) 4866e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; 4876e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg else 4886e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->tx_gain = ((1 << 5) | (5 << 3)); 4896e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg added++; 4906e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } else 4916e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_ERR(priv, "no valid channel found\n"); 4926e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return added; 4936e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg} 4946e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 4956e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Bergstatic int iwl_get_channels_for_scan(struct iwl_priv *priv, 4966e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct ieee80211_vif *vif, 4976e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg enum ieee80211_band band, 4986e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 is_active, u8 n_probes, 4996e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_scan_channel *scan_ch) 5006e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg{ 5016e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct ieee80211_channel *chan; 5026e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg const struct ieee80211_supported_band *sband; 5036e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg const struct iwl_channel_info *ch_info; 5046e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 passive_dwell = 0; 5056e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 active_dwell = 0; 5066e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg int added, i; 5076e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 channel; 5086e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5096e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg sband = iwl_get_hw_mode(priv, band); 5106e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!sband) 5116e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return 0; 5126e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5136e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); 5146e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg passive_dwell = iwl_get_passive_dwell_time(priv, band); 5156e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5166e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (passive_dwell <= active_dwell) 5176e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg passive_dwell = active_dwell + 1; 5186e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5196e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { 5206e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg chan = priv->scan_request->channels[i]; 5216e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5226e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (chan->band != band) 5236e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg continue; 5246e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5256e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg channel = chan->hw_value; 5266e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->channel = cpu_to_le16(channel); 5276e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5286e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg ch_info = iwl_get_channel_info(priv, band, channel); 5296e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!is_channel_valid(ch_info)) { 5306e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, 5316e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg "Channel %d is INVALID for this band.\n", 5326e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg channel); 5336e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg continue; 5346e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 5356e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5366e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!is_active || is_channel_passive(ch_info) || 5376e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) 5386e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; 5396e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg else 5406e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; 5416e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5426e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (n_probes) 5436e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); 5446e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5456e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->active_dwell = cpu_to_le16(active_dwell); 5466e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->passive_dwell = cpu_to_le16(passive_dwell); 5476e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5486e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* Set txpower levels to defaults */ 5496e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->dsp_atten = 110; 5506e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5516e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* NOTE: if we were doing 6Mb OFDM for scans we'd use 5526e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * power level: 5536e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; 5546e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg */ 5556e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (band == IEEE80211_BAND_5GHZ) 5566e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; 5576e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg else 5586e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch->tx_gain = ((1 << 5) | (5 << 3)); 5596e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5606e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n", 5616e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg channel, le32_to_cpu(scan_ch->type), 5626e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? 5636e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg "ACTIVE" : "PASSIVE", 5646e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? 5656e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg active_dwell : passive_dwell); 5666e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5676e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch++; 5686e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg added++; 5696e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 5706e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 5716e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added); 5726e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return added; 5736e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg} 5746e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 575b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg/** 576b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg * iwl_fill_probe_req - fill in all required fields and IE for probe request 577b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg */ 578b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 579b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Bergstatic u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, 580b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg const u8 *ies, int ie_len, int left) 581b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg{ 582b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg int len = 0; 583b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg u8 *pos = NULL; 584b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 585b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg /* Make sure there is enough space for the probe request, 586b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg * two mandatory IEs and the data */ 587b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg left -= 24; 588b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg if (left < 0) 589b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg return 0; 590b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 591b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 592b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); 593b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg memcpy(frame->sa, ta, ETH_ALEN); 594b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); 595b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg frame->seq_ctrl = 0; 596b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 597b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg len += 24; 598b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 599b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg /* ...next IE... */ 600b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg pos = &frame->u.probe_req.variable[0]; 601b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 602b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg /* fill in our indirect SSID IE */ 603b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg left -= 2; 604b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg if (left < 0) 605b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg return 0; 606b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg *pos++ = WLAN_EID_SSID; 607b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg *pos++ = 0; 608b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 609b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg len += 2; 610b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 611b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg if (WARN_ON(left < ie_len)) 612b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg return len; 613b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 614b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg if (ies && ie_len) { 615b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg memcpy(pos, ies, ie_len); 616b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg len += ie_len; 617b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg } 618b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 619b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg return (u16)len; 620b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg} 621b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg 6226e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Bergstatic int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) 6236e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg{ 6246e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_host_cmd cmd = { 6256e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg .id = REPLY_SCAN_CMD, 6266e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg .len = { sizeof(struct iwl_scan_cmd), }, 6276e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg .flags = CMD_SYNC, 6286e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg }; 6296e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_scan_cmd *scan; 6306e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 6316e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u32 rate_flags = 0; 632331d9301ed4d0fe33e9762c62f2870243bcf77ebFabio Estevam u16 cmd_len = 0; 6336e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 rx_chain = 0; 6346e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg enum ieee80211_band band; 6356e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 n_probes = 0; 6366e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 rx_ant = hw_params(priv).valid_rx_ant; 6376e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 rate; 6386e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg bool is_active = false; 6396e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg int chan_mod; 6406e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 active_chains; 6416e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u8 scan_tx_antennas = hw_params(priv).valid_tx_ant; 6426e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg int ret; 6436e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 644b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 6456e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6466e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (vif) 6476e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg ctx = iwl_rxon_ctx_from_vif(vif); 6486e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6496e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!priv->scan_cmd) { 6506e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) + 6516e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_MAX_SCAN_SIZE, GFP_KERNEL); 6526e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!priv->scan_cmd) { 6536e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, 6546e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg "fail to allocate memory for scan\n"); 6556e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return -ENOMEM; 6566e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 6576e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 6586e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan = priv->scan_cmd; 6596e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); 6606e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6616e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; 6626e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->quiet_time = IWL_ACTIVE_QUIET_TIME; 6636e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6646e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (priv->scan_type != IWL_SCAN_ROC && 6656e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg iwl_is_any_associated(priv)) { 6666e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u16 interval = 0; 6676e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u32 extra; 6686e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u32 suspend_time = 100; 6696e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg u32 scan_suspend_time = 100; 6706e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6716e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); 6726e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg switch (priv->scan_type) { 6736e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_ROC: 6746e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg WARN_ON(1); 6756e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 6766e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_RADIO_RESET: 6776e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg interval = 0; 6786e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 6796e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_NORMAL: 6806e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg interval = vif->bss_conf.beacon_int; 6816e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 6826e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 6836e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6846e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->suspend_time = 0; 6856e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->max_out_time = cpu_to_le32(200 * 1024); 6866e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!interval) 6876e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg interval = suspend_time; 6886e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 6896e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg extra = (suspend_time / interval) << 22; 6906e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_suspend_time = (extra | 6916e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg ((suspend_time % interval) * 1024)); 6926e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->suspend_time = cpu_to_le32(scan_suspend_time); 6936e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", 6946e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_suspend_time, interval); 6956e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } else if (priv->scan_type == IWL_SCAN_ROC) { 6966e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->suspend_time = 0; 6976e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->max_out_time = 0; 6986e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->quiet_time = 0; 6996e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->quiet_plcp_th = 0; 7006e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 7016e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7026e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg switch (priv->scan_type) { 7036e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_RADIO_RESET: 7046e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); 7056e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 7066e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_NORMAL: 7076e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (priv->scan_request->n_ssids) { 7086e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg int i, p = 0; 7096e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); 7106e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg for (i = 0; i < priv->scan_request->n_ssids; i++) { 7116e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* always does wildcard anyway */ 7126e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!priv->scan_request->ssids[i].ssid_len) 7136e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg continue; 7146e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->direct_scan[p].id = WLAN_EID_SSID; 7156e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->direct_scan[p].len = 7166e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_request->ssids[i].ssid_len; 7176e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg memcpy(scan->direct_scan[p].ssid, 7186e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_request->ssids[i].ssid, 7196e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_request->ssids[i].ssid_len); 7206e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg n_probes++; 7216e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg p++; 7226e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 7236e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg is_active = true; 7246e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } else 7256e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); 7266e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 7276e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_ROC: 7286e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "Start ROC scan.\n"); 7296e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 7306e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 7316e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7326e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; 7336e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.sta_id = ctx->bcast_sta_id; 7346e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; 7356e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7366e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg switch (priv->scan_band) { 7376e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IEEE80211_BAND_2GHZ: 7386e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; 7396e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg chan_mod = le32_to_cpu( 7406e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->contexts[IWL_RXON_CTX_BSS].active.flags & 7416e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg RXON_FLG_CHANNEL_MODE_MSK) 7426e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg >> RXON_FLG_CHANNEL_MODE_POS; 7433a8aea098c8ebe3437d877542d138085be33346cJohannes Berg if ((priv->scan_request && priv->scan_request->no_cck) || 7443a8aea098c8ebe3437d877542d138085be33346cJohannes Berg chan_mod == CHANNEL_MODE_PURE_40) { 7456e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rate = IWL_RATE_6M_PLCP; 7466e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } else { 7476e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rate = IWL_RATE_1M_PLCP; 7486e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rate_flags = RATE_MCS_CCK_MSK; 7496e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 7506e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* 7516e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * Internal scans are passive, so we can indiscriminately set 7526e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * the BT ignore flag on 2.4 GHz since it applies to TX only. 7536e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg */ 7543862241945026a8fa165ab73c57739df77b8e1fbDon Fry if (cfg(priv)->bt_params && 7553862241945026a8fa165ab73c57739df77b8e1fbDon Fry cfg(priv)->bt_params->advanced_bt_coexist) 7566e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; 7576e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 7586e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IEEE80211_BAND_5GHZ: 7596e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rate = IWL_RATE_6M_PLCP; 7606e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 7616e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg default: 7626e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_WARN(priv, "Invalid scan band\n"); 7636e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return -EIO; 7646e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 7656e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7666e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* 7676e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * If active scanning is requested but a certain channel is 7686e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * marked passive, we can do active scanning if we detect 7696e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * transmissions. 7706e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * 7716e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * There is an issue with some firmware versions that triggers 7726e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * a sysassert on a "good CRC threshold" of zero (== disabled), 7736e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * on a radar channel even though this means that we should NOT 7746e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * send probes. 7756e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * 7766e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * The "good CRC threshold" is the number of frames that we 7776e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * need to receive during our dwell time on a channel before 7786e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * sending out probes -- setting this to a huge value will 7796e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * mean we never reach it, but at the same time work around 7806e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER 7816e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * here instead of IWL_GOOD_CRC_TH_DISABLED. 7826e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * 7836e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * This was fixed in later versions along with some other 7846e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * scan changes, and the threshold behaves as a flag in those 7856e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg * versions. 7866e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg */ 7876e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (priv->new_scan_threshold_behaviour) 7886e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : 7896e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_GOOD_CRC_TH_DISABLED; 7906e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg else 7916e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : 7926e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_GOOD_CRC_TH_NEVER; 7936e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7946e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg band = priv->scan_band; 7956e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7963862241945026a8fa165ab73c57739df77b8e1fbDon Fry if (cfg(priv)->scan_rx_antennas[band]) 7973862241945026a8fa165ab73c57739df77b8e1fbDon Fry rx_ant = cfg(priv)->scan_rx_antennas[band]; 7986e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 7996e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (band == IEEE80211_BAND_2GHZ && 8003862241945026a8fa165ab73c57739df77b8e1fbDon Fry cfg(priv)->bt_params && 8013862241945026a8fa165ab73c57739df77b8e1fbDon Fry cfg(priv)->bt_params->advanced_bt_coexist) { 8026e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* transmit 2.4 GHz probes only on first antenna */ 8036e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_tx_antennas = first_antenna(scan_tx_antennas); 8046e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 8056e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8066e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, 8076e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_tx_ant[band], 8086e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_tx_antennas); 8096e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); 8106e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); 8116e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8126e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* In power save mode use one chain, otherwise use all chains */ 8136e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) { 8146e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* rx_ant has been set to all valid chains previously */ 8156e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg active_chains = rx_ant & 8166e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg ((u8)(priv->chain_noise_data.active_chains)); 8176e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (!active_chains) 8186e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg active_chains = rx_ant; 8196e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8206e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", 8216e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->chain_noise_data.active_chains); 8226e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8236e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_ant = first_antenna(active_chains); 8246e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 8253862241945026a8fa165ab73c57739df77b8e1fbDon Fry if (cfg(priv)->bt_params && 8263862241945026a8fa165ab73c57739df77b8e1fbDon Fry cfg(priv)->bt_params->advanced_bt_coexist && 8276e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->bt_full_concurrent) { 8286e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* operated as 1x1 in full concurrency mode */ 8296e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_ant = first_antenna(rx_ant); 8306e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 8316e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8326e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* MIMO is not used here, but value is required */ 8336e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_chain |= 8346e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS; 8356e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; 8366e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; 8376e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; 8386e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->rx_chain = cpu_to_le16(rx_chain); 8396e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg switch (priv->scan_type) { 8406e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_NORMAL: 841b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg cmd_len = iwl_fill_probe_req( 8426e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (struct ieee80211_mgmt *)scan->data, 8436e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg vif->addr, 8446e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_request->ie, 8456e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg priv->scan_request->ie_len, 8466e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_MAX_SCAN_SIZE - sizeof(*scan)); 8476e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 8486e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_RADIO_RESET: 8496e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_ROC: 8506e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* use bcast addr, will not be transmitted but must be valid */ 851b443d8d8a2b4c3def4b47c17a44bb17ea0a3202fJohannes Berg cmd_len = iwl_fill_probe_req( 8526e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (struct ieee80211_mgmt *)scan->data, 8536e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg iwl_bcast_addr, NULL, 0, 8546e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_MAX_SCAN_SIZE - sizeof(*scan)); 8556e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 8566e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg default: 8576e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg BUG(); 8586e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 8596e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->tx_cmd.len = cpu_to_le16(cmd_len); 8606e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8616e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | 8626e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg RXON_FILTER_BCON_AWARE_MSK); 8636e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8646e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg switch (priv->scan_type) { 8656e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_RADIO_RESET: 8666e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->channel_count = 8676e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg iwl_get_single_channel_for_scan(priv, vif, band, 8686e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (void *)&scan->data[cmd_len]); 8696e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 8706e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_NORMAL: 8716e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->channel_count = 8726e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg iwl_get_channels_for_scan(priv, vif, band, 8736e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg is_active, n_probes, 8746e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg (void *)&scan->data[cmd_len]); 8756e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 8766e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg case IWL_SCAN_ROC: { 8776e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg struct iwl_scan_channel *scan_ch; 878390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg int n_chan, i; 879390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg u16 dwell; 880390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 881390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg dwell = iwl_limit_dwell(priv, priv->hw_roc_duration); 882390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell); 8836e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 884390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan->channel_count = n_chan; 8856e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 8866e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan_ch = (void *)&scan->data[cmd_len]; 8876e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 888390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg for (i = 0; i < n_chan; i++) { 889390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; 890390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->channel = 891390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg cpu_to_le16(priv->hw_roc_channel->hw_value); 8926e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 893390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg if (i == n_chan - 1) 894390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg dwell = priv->hw_roc_duration - i * dwell; 895390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 896390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->active_dwell = 897390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->passive_dwell = cpu_to_le16(dwell); 898390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 899390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg /* Set txpower levels to defaults */ 900390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->dsp_atten = 110; 901390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 902390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg /* NOTE: if we were doing 6Mb OFDM for scans we'd use 903390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg * power level: 904390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; 905390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg */ 906390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ) 907390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; 908390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg else 909390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch->tx_gain = ((1 << 5) | (5 << 3)); 910390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 911390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg scan_ch++; 9126e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 913390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg } 914390808db4ab5c658dc1eb8078d82027ce7d0ea78Johannes Berg 9156e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg break; 9166e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 9176e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 9186e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (scan->channel_count == 0) { 9196e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); 9206e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return -EIO; 9216e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 9226e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 9236e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) + 9246e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->channel_count * sizeof(struct iwl_scan_channel); 9256e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg cmd.data[0] = scan; 9266e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; 9276e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg scan->len = cpu_to_le16(cmd.len[0]); 9286e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 9296e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg /* set scan bit here for PAN params */ 93083626404a70da74c67f32f119e53c0ba032ba2d8Don Fry set_bit(STATUS_SCAN_HW, &priv->status); 9316e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 9326e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg ret = iwlagn_set_pan_params(priv); 9336e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (ret) 9346e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return ret; 9356e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 936e10a0533a9172471b52bd9512838d766420a3bafJohannes Berg ret = iwl_dvm_send_cmd(priv, &cmd); 9376e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg if (ret) { 93883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCAN_HW, &priv->status); 9396e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg iwlagn_set_pan_params(priv); 9406e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg } 9416e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 9426e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg return ret; 9436e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg} 9446e809a16d98efa8b1483a25ab8886dd2aa200d0fJohannes Berg 945f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winklervoid iwl_init_scan_params(struct iwl_priv *priv) 946f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler{ 947d618912417fbce4f6514fe1cbef7df2e73bdb6c2Emmanuel Grumbach u8 ant_idx = fls(hw_params(priv).valid_tx_ant) - 1; 948f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) 94976eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; 950f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) 95176eff18bdc5feaa53f1be33709b67df02f1d55e9Tomas Winkler priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; 952f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler} 953f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 954266af4c745952e9bebf687dd68af58df553cb59dJohannes Bergint __must_check iwl_scan_initiate(struct iwl_priv *priv, 955266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg struct ieee80211_vif *vif, 956266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg enum iwl_scan_type scan_type, 957266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg enum ieee80211_band band) 9582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 9593eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg int ret; 9603eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 961b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg lockdep_assert_held(&priv->mutex); 96288be026490ed89c2ffead81a52531fbac5507e01Johannes Berg 9633eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg cancel_delayed_work(&priv->scan_check); 9643eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 96583626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (!iwl_is_ready_rf(priv)) { 9667cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_WARN(priv, "Request scan called when driver not ready.\n"); 9673eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg return -EIO; 9683eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg } 9693eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 97083626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (test_bit(STATUS_SCAN_HW, &priv->status)) { 9717cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, 9723eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg "Multiple concurrent scan requests in parallel.\n"); 9733eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg return -EBUSY; 9743eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg } 9753eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 97683626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 9777cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n"); 9783eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg return -EBUSY; 9793eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg } 9803eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 9817cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", 982266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg scan_type == IWL_SCAN_NORMAL ? "" : 983c6baf7fb40cb141c4b510372f7dac829621ccf3fJohannes Berg scan_type == IWL_SCAN_ROC ? "remain-on-channel " : 984266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg "internal short "); 9853eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg 98683626404a70da74c67f32f119e53c0ba032ba2d8Don Fry set_bit(STATUS_SCANNING, &priv->status); 987266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg priv->scan_type = scan_type; 9882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_start = jiffies; 9893eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg priv->scan_band = band; 9902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9915c3d29fc0d083e674c09407f1bc78e9dbf4ae8a5Don Fry ret = iwlagn_request_scan(priv, vif); 9923eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg if (ret) { 99383626404a70da74c67f32f119e53c0ba032ba2d8Don Fry clear_bit(STATUS_SCANNING, &priv->status); 994266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg priv->scan_type = IWL_SCAN_NORMAL; 9953eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg return ret; 9963eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg } 997b6e4c55aaee4fd40526a6816e60c68dd62e565c4Johannes Berg 9981ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_delayed_work(priv->workqueue, &priv->scan_check, 9993eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg IWL_SCAN_CHECK_WATCHDOG); 10002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 10012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 10022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 10032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1004e9dde6f6edf9954e2c75d2d738cae0f00e9b0fbcAbhijeet Kolekar 1005afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy/* 1006afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy * internal short scan, this function should only been called while associated. 1007afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy * It will reset and tune the radio to prevent possible RF related problem 1008afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy */ 100988be026490ed89c2ffead81a52531fbac5507e01Johannes Bergvoid iwl_internal_short_hw_scan(struct iwl_priv *priv) 1010afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy{ 10111ee158d83853a9f5c1465be56d56ff56e6698e92Johannes Berg queue_work(priv->workqueue, &priv->start_internal_scan); 101288be026490ed89c2ffead81a52531fbac5507e01Johannes Berg} 101388be026490ed89c2ffead81a52531fbac5507e01Johannes Berg 1014c240879f3488ae0904a7ba5bdaaa54638b2d8852Stanislaw Gruszkastatic void iwl_bg_start_internal_scan(struct work_struct *work) 101588be026490ed89c2ffead81a52531fbac5507e01Johannes Berg{ 101688be026490ed89c2ffead81a52531fbac5507e01Johannes Berg struct iwl_priv *priv = 101788be026490ed89c2ffead81a52531fbac5507e01Johannes Berg container_of(work, struct iwl_priv, start_internal_scan); 101888be026490ed89c2ffead81a52531fbac5507e01Johannes Berg 10197cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Start internal scan\n"); 10207cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka 1021b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_lock(&priv->mutex); 1022afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy 1023266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg if (priv->scan_type == IWL_SCAN_RADIO_RESET) { 1024073d5eab6fc85b6c278d507a5633b759a85dc878Reinette Chatre IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); 1025073d5eab6fc85b6c278d507a5633b759a85dc878Reinette Chatre goto unlock; 1026073d5eab6fc85b6c278d507a5633b759a85dc878Reinette Chatre } 1027073d5eab6fc85b6c278d507a5633b759a85dc878Reinette Chatre 102883626404a70da74c67f32f119e53c0ba032ba2d8Don Fry if (test_bit(STATUS_SCANNING, &priv->status)) { 1029afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); 103088be026490ed89c2ffead81a52531fbac5507e01Johannes Berg goto unlock; 1031afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy } 103288be026490ed89c2ffead81a52531fbac5507e01Johannes Berg 1033266af4c745952e9bebf687dd68af58df553cb59dJohannes Berg if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band)) 10343eecce527c7434dfd16517ce08b49632c8a26717Johannes Berg IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); 103588be026490ed89c2ffead81a52531fbac5507e01Johannes Berg unlock: 1036b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_unlock(&priv->mutex); 1037afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy} 1038afbdd69af0e6a0c40676d4d4b94a0a4414708eaaWey-Yi Guy 1039c240879f3488ae0904a7ba5bdaaa54638b2d8852Stanislaw Gruszkastatic void iwl_bg_scan_check(struct work_struct *data) 10402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 10412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_priv *priv = 10422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler container_of(data, struct iwl_priv, scan_check.work); 10432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 10447cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Scan check work\n"); 10457cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka 1046e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka /* Since we are here firmware does not finish scan and 1047e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka * most likely is in bad shape, so we don't bother to 1048e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka * send abort command, just force scan complete to mac80211 */ 1049b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_lock(&priv->mutex); 1050e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka iwl_force_scan_end(priv); 1051b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_unlock(&priv->mutex); 10522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 105377fecfb88f8ad64420e06a96f1bd3b38498bfb4fSamuel Ortiz 1054c240879f3488ae0904a7ba5bdaaa54638b2d8852Stanislaw Gruszkastatic void iwl_bg_abort_scan(struct work_struct *work) 10552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 10562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); 10572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 10587cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka IWL_DEBUG_SCAN(priv, "Abort scan work\n"); 10597cf24421292d92556d53630e6973b34324c94103Stanislaw Gruszka 1060e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka /* We keep scan_check work queued in case when firmware will not 1061e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka * report back scan completed notification */ 1062b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_lock(&priv->mutex); 10636bd1758d978f917dc0804f44e3528ef1a80d9d43Stanislaw Gruszka iwl_scan_cancel_timeout(priv, 200); 1064b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_unlock(&priv->mutex); 10652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 10662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1067f253247a944fcf5f48ca434331d9e4f72f5fef8dJohannes Bergstatic void iwl_bg_scan_completed(struct work_struct *work) 1068f253247a944fcf5f48ca434331d9e4f72f5fef8dJohannes Berg{ 1069f253247a944fcf5f48ca434331d9e4f72f5fef8dJohannes Berg struct iwl_priv *priv = 1070f253247a944fcf5f48ca434331d9e4f72f5fef8dJohannes Berg container_of(work, struct iwl_priv, scan_completed); 107152a02d1500e4cbb347006e407d1c0bd941eee7fcJohannes Berg 1072b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_lock(&priv->mutex); 1073f253247a944fcf5f48ca434331d9e4f72f5fef8dJohannes Berg iwl_process_scan_complete(priv); 1074b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_unlock(&priv->mutex); 1075eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler} 1076eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler 10772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_scan_deferred_work(struct iwl_priv *priv) 10782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 1079eedda3670ea8e6d7649e3c8847759b0a6e532f8dTomas Winkler INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); 10802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); 108188be026490ed89c2ffead81a52531fbac5507e01Johannes Berg INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan); 10822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); 10832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 10842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1085e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszkavoid iwl_cancel_scan_deferred_work(struct iwl_priv *priv) 1086e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka{ 1087e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka cancel_work_sync(&priv->start_internal_scan); 1088e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka cancel_work_sync(&priv->abort_scan); 1089e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka cancel_work_sync(&priv->scan_completed); 1090e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka 1091e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka if (cancel_delayed_work_sync(&priv->scan_check)) { 1092b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_lock(&priv->mutex); 1093e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka iwl_force_scan_end(priv); 1094b1eea297d6b522b801c95b60b1e64fb61228c6c7Johannes Berg mutex_unlock(&priv->mutex); 1095e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka } 1096e7e16b90b477a07d17af37dceb2e8af1ddbd9712Stanislaw Gruszka} 1097