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