iwl-scan.c 17.1 KB
Newer Older
1 2 3 4
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
5
 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
 * USA
 *
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.GPL.
 *
 * Contact Information:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
26 27
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *****************************************************************************/
28
#include <linux/slab.h>
29
#include <linux/types.h>
30
#include <linux/etherdevice.h>
31
#include <net/mac80211.h>
32 33 34 35 36 37 38 39 40 41 42

#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"

/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
 * sending probe req.  This should be set long enough to hear probe responses
 * from more than one AP.  */
T
Tomas Winkler 已提交
43 44 45 46 47
#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
#define IWL_ACTIVE_DWELL_TIME_52    (20)

#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
48 49 50 51 52 53 54 55 56

/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
 * Must be set longer than active dwell time.
 * For the most reliable scan, set > AP beacon interval (typically 100msec). */
#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
#define IWL_PASSIVE_DWELL_TIME_52   (10)
#define IWL_PASSIVE_DWELL_BASE      (100)
#define IWL_CHANNEL_TUNE_TIME       5

57 58 59 60 61 62 63 64
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
	int ret;
	struct iwl_rx_packet *pkt;
	struct iwl_host_cmd cmd = {
		.id = REPLY_SCAN_ABORT_CMD,
		.flags = CMD_WANT_SKB,
	};
T
Tomas Winkler 已提交
65

66 67 68 69 70 71 72 73 74
	/* Exit instantly with error when device is not ready
	 * to receive scan abort command or it does not perform
	 * hardware scan currently */
	if (!test_bit(STATUS_READY, &priv->status) ||
	    !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
	    test_bit(STATUS_FW_ERROR, &priv->status) ||
	    test_bit(STATUS_EXIT_PENDING, &priv->status))
		return -EIO;
T
Tomas Winkler 已提交
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89
	ret = iwl_send_cmd_sync(priv, &cmd);
	if (ret)
		return ret;

	pkt = (struct iwl_rx_packet *)cmd.reply_page;
	if (pkt->u.status != CAN_ABORT_STATUS) {
		/* The scan abort will return 1 for success or
		 * 2 for "failure".  A failure condition can be
		 * due to simply not being in an active scan which
		 * can occur if we send the scan abort before we
		 * the microcode has notified us that a scan is
		 * completed. */
		IWL_DEBUG_INFO(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
		ret = -EIO;
90 91
	}

92 93 94
	iwl_free_pages(priv, cmd.reply_page);
	return ret;
}
95

96 97 98 99 100 101 102 103 104 105 106 107 108
static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{
	/* check if scan was requested from mac80211 */
	if (priv->scan_request) {
		IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
		ieee80211_scan_completed(priv->hw, aborted);
	}

	priv->is_internal_short_scan = false;
	priv->scan_vif = NULL;
	priv->scan_request = NULL;
}

109 110 111 112 113 114 115 116 117
static void iwl_force_scan_end(struct iwl_priv *priv)
{
	IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
	clear_bit(STATUS_SCANNING, &priv->status);
	clear_bit(STATUS_SCAN_HW, &priv->status);
	clear_bit(STATUS_SCAN_ABORTING, &priv->status);
	iwl_complete_scan(priv, true);
}

118 119 120
static void iwl_do_scan_abort(struct iwl_priv *priv)
{
	int ret;
121

122 123 124 125 126
	lockdep_assert_held(&priv->mutex);

	if (!test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
		return;
127 128
	}

129 130 131 132 133 134 135 136
	if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
		return;
	}

	ret = iwl_send_scan_abort(priv);
	if (ret) {
		IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
137
		iwl_force_scan_end(priv);
138 139 140 141 142 143 144 145 146 147
	} else
		IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n");
}

/**
 * iwl_scan_cancel - Cancel any currently executing HW scan
 */
int iwl_scan_cancel(struct iwl_priv *priv)
{
	IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
148
	queue_work(priv->workqueue, &priv->abort_scan);
149 150 151
	return 0;
}
EXPORT_SYMBOL(iwl_scan_cancel);
152

153 154 155 156 157 158 159
/**
 * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
 * @ms: amount of time to wait (in milliseconds) for scan to abort
 *
 */
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
{
160
	int ret;
161 162 163
	unsigned long timeout = jiffies + msecs_to_jiffies(ms);

	lockdep_assert_held(&priv->mutex);
164

165
	IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
166

167 168 169 170 171 172
	iwl_do_scan_abort(priv);

	while (time_before_eq(jiffies, timeout)) {
		if (!test_bit(STATUS_SCAN_HW, &priv->status))
			break;
		msleep(20);
173 174
	}

175 176 177 178
	ret = test_bit(STATUS_SCAN_HW, &priv->status);
	if (ret)
		iwl_force_scan_end(priv);
	return ret;
179 180 181 182 183 184 185 186
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);

/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
			      struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
Z
Zhu Yi 已提交
187
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
188 189 190
	struct iwl_scanreq_notification *notif =
	    (struct iwl_scanreq_notification *)pkt->u.raw;

191
	IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
192 193 194 195 196 197 198
#endif
}

/* Service SCAN_START_NOTIFICATION (0x82) */
static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
				    struct iwl_rx_mem_buffer *rxb)
{
Z
Zhu Yi 已提交
199
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
200 201 202
	struct iwl_scanstart_notification *notif =
	    (struct iwl_scanstart_notification *)pkt->u.raw;
	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
203
	IWL_DEBUG_SCAN(priv, "Scan start: "
204 205 206 207
		       "%d [802.11%s] "
		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
		       notif->channel,
		       notif->band ? "bg" : "a",
T
Tomas Winkler 已提交
208 209 210
		       le32_to_cpu(notif->tsf_high),
		       le32_to_cpu(notif->tsf_low),
		       notif->status, notif->beacon_timer);
211 212 213 214 215 216 217
}

/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
				      struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
Z
Zhu Yi 已提交
218
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
219 220 221
	struct iwl_scanresults_notification *notif =
	    (struct iwl_scanresults_notification *)pkt->u.raw;

222
	IWL_DEBUG_SCAN(priv, "Scan ch.res: "
223 224
		       "%d [802.11%s] "
		       "(TSF: 0x%08X:%08X) - %d "
225
		       "elapsed=%lu usec\n",
226 227 228 229 230
		       notif->channel,
		       notif->band ? "bg" : "a",
		       le32_to_cpu(notif->tsf_high),
		       le32_to_cpu(notif->tsf_low),
		       le32_to_cpu(notif->statistics[0]),
231
		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
232 233 234 235 236 237 238
#endif
}

/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
				       struct iwl_rx_mem_buffer *rxb)
{
Z
Zhu Yi 已提交
239
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
240 241
	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;

242
	IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
243 244 245 246 247 248 249
		       scan_notif->scanned_channels,
		       scan_notif->tsf_low,
		       scan_notif->tsf_high, scan_notif->status);

	/* The HW is no longer scanning */
	clear_bit(STATUS_SCAN_HW, &priv->status);

J
Johannes Berg 已提交
250
	IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
J
Johannes Berg 已提交
251
		       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
252
		       jiffies_to_msecs(elapsed_jiffies
J
Johannes Berg 已提交
253
					(priv->scan_start, jiffies)));
254

255
	queue_work(priv->workqueue, &priv->scan_completed);
256

257
	if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
258 259
	    priv->cfg->advanced_bt_coexist &&
	    priv->bt_status != scan_notif->bt_status) {
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
		if (scan_notif->bt_status) {
			/* BT on */
			if (!priv->bt_ch_announce)
				priv->bt_traffic_load =
					IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
			/*
			 * otherwise, no traffic load information provided
			 * no changes made
			 */
		} else {
			/* BT off */
			priv->bt_traffic_load =
				IWL_BT_COEX_TRAFFIC_LOAD_NONE;
		}
		priv->bt_status = scan_notif->bt_status;
		queue_work(priv->workqueue, &priv->bt_traffic_change_work);
	}
277 278 279 280 281 282 283 284 285 286 287 288 289 290
}

void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
{
	/* scan handlers */
	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
					iwl_rx_scan_results_notif;
	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
					iwl_rx_scan_complete_notif;
}
EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);

S
Samuel Ortiz 已提交
291 292 293
inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
				     enum ieee80211_band band,
				     u8 n_probes)
294 295
{
	if (band == IEEE80211_BAND_5GHZ)
T
Tomas Winkler 已提交
296 297
		return IWL_ACTIVE_DWELL_TIME_52 +
			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
298
	else
T
Tomas Winkler 已提交
299 300
		return IWL_ACTIVE_DWELL_TIME_24 +
			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
301
}
S
Samuel Ortiz 已提交
302
EXPORT_SYMBOL(iwl_get_active_dwell_time);
303

S
Samuel Ortiz 已提交
304
u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
305 306
			       enum ieee80211_band band,
			       struct ieee80211_vif *vif)
307
{
308
	struct iwl_rxon_context *ctx;
T
Tomas Winkler 已提交
309
	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
310 311 312
	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;

313
	if (iwl_is_any_associated(priv)) {
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		/*
		 * If we're associated, we clamp the maximum passive
		 * dwell time to be 98% of the smallest beacon interval
		 * (minus 2 * channel tune time)
		 */
		for_each_context(priv, ctx) {
			u16 value;

			if (!iwl_is_associated_ctx(ctx))
				continue;
			value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
			if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
				value = IWL_PASSIVE_DWELL_BASE;
			value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
			passive = min(value, passive);
		}
330 331 332 333
	}

	return passive;
}
S
Samuel Ortiz 已提交
334
EXPORT_SYMBOL(iwl_get_passive_dwell_time);
335

T
Tomas Winkler 已提交
336 337
void iwl_init_scan_params(struct iwl_priv *priv)
{
T
Tomas Winkler 已提交
338
	u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
T
Tomas Winkler 已提交
339
	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
T
Tomas Winkler 已提交
340
		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
T
Tomas Winkler 已提交
341
	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
T
Tomas Winkler 已提交
342
		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
T
Tomas Winkler 已提交
343
}
344
EXPORT_SYMBOL(iwl_init_scan_params);
T
Tomas Winkler 已提交
345

J
Johannes Berg 已提交
346 347 348 349
static int __must_check iwl_scan_initiate(struct iwl_priv *priv,
					  struct ieee80211_vif *vif,
					  bool internal,
					  enum nl80211_band band)
350
{
J
Johannes Berg 已提交
351 352
	int ret;

J
Johannes Berg 已提交
353
	lockdep_assert_held(&priv->mutex);
J
Johannes Berg 已提交
354

J
Johannes Berg 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	if (WARN_ON(!priv->cfg->ops->utils->request_scan))
		return -EOPNOTSUPP;

	cancel_delayed_work(&priv->scan_check);

	if (!iwl_is_ready(priv)) {
		IWL_WARN(priv, "request scan called when driver not ready.\n");
		return -EIO;
	}

	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
		IWL_DEBUG_INFO(priv,
			"Multiple concurrent scan requests in parallel.\n");
		return -EBUSY;
	}

	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
		return -EIO;
	}

	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_HC(priv, "Scan request while abort pending.\n");
		return -EBUSY;
	}

	if (iwl_is_rfkill(priv)) {
		IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
		return -EIO;
	}

	if (!test_bit(STATUS_READY, &priv->status)) {
		IWL_DEBUG_HC(priv, "Scan request while uninitialized.\n");
		return -EBUSY;
	}

	IWL_DEBUG_INFO(priv, "Starting %sscan...\n",
			internal ? "internal short " : "");

394
	set_bit(STATUS_SCANNING, &priv->status);
J
Johannes Berg 已提交
395
	priv->is_internal_short_scan = internal;
396
	priv->scan_start = jiffies;
J
Johannes Berg 已提交
397
	priv->scan_band = band;
398

J
Johannes Berg 已提交
399 400 401 402 403 404
	ret = priv->cfg->ops->utils->request_scan(priv, vif);
	if (ret) {
		clear_bit(STATUS_SCANNING, &priv->status);
		priv->is_internal_short_scan = false;
		return ret;
	}
405

J
Johannes Berg 已提交
406 407
	queue_delayed_work(priv->workqueue, &priv->scan_check,
			   IWL_SCAN_CHECK_WATCHDOG);
408 409 410 411

	return 0;
}

412
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
413 414
		    struct ieee80211_vif *vif,
		    struct cfg80211_scan_request *req)
415 416
{
	struct iwl_priv *priv = hw->priv;
J
Johannes Berg 已提交
417
	int ret;
418 419 420

	IWL_DEBUG_MAC80211(priv, "enter\n");

J
Johannes Berg 已提交
421 422 423
	if (req->n_channels == 0)
		return -EINVAL;

424 425
	mutex_lock(&priv->mutex);

426 427
	if (test_bit(STATUS_SCANNING, &priv->status) &&
	    !priv->is_internal_short_scan) {
R
Reinette Chatre 已提交
428 429 430 431 432
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
		ret = -EAGAIN;
		goto out_unlock;
	}

J
Johannes Berg 已提交
433
	/* mac80211 will only ask for one band at a time */
J
Johannes Berg 已提交
434
	priv->scan_request = req;
435
	priv->scan_vif = vif;
436

437 438 439 440 441 442 443
	/*
	 * If an internal scan is in progress, just set
	 * up the scan_request as per above.
	 */
	if (priv->is_internal_short_scan)
		ret = 0;
	else
J
Johannes Berg 已提交
444 445
		ret = iwl_scan_initiate(priv, vif, false,
					req->channels[0]->band);
446 447 448 449 450 451 452 453 454 455

	IWL_DEBUG_MAC80211(priv, "leave\n");

out_unlock:
	mutex_unlock(&priv->mutex);

	return ret;
}
EXPORT_SYMBOL(iwl_mac_hw_scan);

456 457 458 459
/*
 * internal short scan, this function should only been called while associated.
 * It will reset and tune the radio to prevent possible RF related problem
 */
J
Johannes Berg 已提交
460
void iwl_internal_short_hw_scan(struct iwl_priv *priv)
461
{
J
Johannes Berg 已提交
462 463 464
	queue_work(priv->workqueue, &priv->start_internal_scan);
}

465
static void iwl_bg_start_internal_scan(struct work_struct *work)
J
Johannes Berg 已提交
466 467 468 469 470
{
	struct iwl_priv *priv =
		container_of(work, struct iwl_priv, start_internal_scan);

	mutex_lock(&priv->mutex);
471

472 473 474 475 476
	if (priv->is_internal_short_scan == true) {
		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
		goto unlock;
	}

477 478
	if (test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
J
Johannes Berg 已提交
479
		goto unlock;
480
	}
J
Johannes Berg 已提交
481

J
Johannes Berg 已提交
482 483
	if (iwl_scan_initiate(priv, NULL, true, priv->band))
		IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
J
Johannes Berg 已提交
484 485
 unlock:
	mutex_unlock(&priv->mutex);
486 487
}

488
static void iwl_bg_scan_check(struct work_struct *data)
489 490 491 492 493
{
	struct iwl_priv *priv =
	    container_of(data, struct iwl_priv, scan_check.work);

	mutex_lock(&priv->mutex);
494
	iwl_scan_cancel_timeout(priv, 200);
495 496
	mutex_unlock(&priv->mutex);
}
S
Samuel Ortiz 已提交
497

498 499 500
/**
 * iwl_fill_probe_req - fill in all required fields and IE for probe request
 */
T
Tomas Winkler 已提交
501

J
Johannes Berg 已提交
502
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
503
		       const u8 *ta, const u8 *ies, int ie_len, int left)
504 505 506
{
	int len = 0;
	u8 *pos = NULL;
T
Tomas Winkler 已提交
507

508 509 510 511 512 513 514 515
	/* Make sure there is enough space for the probe request,
	 * two mandatory IEs and the data */
	left -= 24;
	if (left < 0)
		return 0;

	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
516
	memcpy(frame->sa, ta, ETH_ALEN);
517 518 519
	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
	frame->seq_ctrl = 0;

T
Tomas Winkler 已提交
520 521
	len += 24;

522
	/* ...next IE... */
T
Tomas Winkler 已提交
523
	pos = &frame->u.probe_req.variable[0];
524

T
Tomas Winkler 已提交
525
	/* fill in our indirect SSID IE */
526 527 528 529
	left -= 2;
	if (left < 0)
		return 0;
	*pos++ = WLAN_EID_SSID;
530 531 532
	*pos++ = 0;

	len += 2;
533

J
Johannes Berg 已提交
534 535
	if (WARN_ON(left < ie_len))
		return len;
536

537
	if (ies && ie_len) {
538
		memcpy(pos, ies, ie_len);
539 540
		len += ie_len;
	}
T
Tomas Winkler 已提交
541

542 543
	return (u16)len;
}
S
Samuel Ortiz 已提交
544
EXPORT_SYMBOL(iwl_fill_probe_req);
545

546
static void iwl_bg_abort_scan(struct work_struct *work)
547 548 549
{
	struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);

S
Stanislaw Gruszka 已提交
550
	cancel_delayed_work(&priv->scan_check);
551

S
Stanislaw Gruszka 已提交
552
	mutex_lock(&priv->mutex);
553
	iwl_scan_cancel_timeout(priv, 200);
554 555 556
	mutex_unlock(&priv->mutex);
}

557
static void iwl_bg_scan_completed(struct work_struct *work)
558 559 560
{
	struct iwl_priv *priv =
	    container_of(work, struct iwl_priv, scan_completed);
561
	bool aborted;
562
	struct iwl_rxon_context *ctx;
563

564 565
	IWL_DEBUG_INFO(priv, "Completed %sscan.\n",
		       priv->is_internal_short_scan ? "internal short " : "");
566

567 568
	cancel_delayed_work(&priv->scan_check);

569
	mutex_lock(&priv->mutex);
570 571 572 573 574

	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
	if (aborted)
		IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");

575 576 577
	if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_INFO(priv, "Scan already completed.\n");
		goto out;
578
	}
579

580 581
	if (priv->is_internal_short_scan && !aborted) {
		int err;
582

583 584 585
		/* Check if mac80211 requested scan during our internal scan */
		if (priv->scan_request == NULL)
			goto out_complete;
J
Johannes Berg 已提交
586

587 588 589
		/* If so request a new scan */
		err = iwl_scan_initiate(priv, priv->scan_vif, false,
					priv->scan_request->channels[0]->band);
J
Johannes Berg 已提交
590 591 592
		if (err) {
			IWL_DEBUG_SCAN(priv,
				"failed to initiate pending scan: %d\n", err);
593 594 595 596 597
			aborted = true;
			goto out_complete;
		}

		goto out;
J
Johannes Berg 已提交
598
	}
599

600 601 602 603 604 605 606
out_complete:
	iwl_complete_scan(priv, aborted);

	/* Can we still talk to firmware ? */
	if (!iwl_is_ready_rf(priv))
		goto out;

607 608 609
	/* Since setting the TXPOWER may have been deferred while
	 * performing the scan, fire one off */
	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
610 611 612 613 614

	/*
	 * Since setting the RXON may have been deferred while
	 * performing the scan, fire one off if needed
	 */
615 616
	for_each_context(priv, ctx)
		iwlcore_commit_rxon(priv, ctx);
617

J
Johannes Berg 已提交
618 619 620
	if (priv->cfg->ops->hcmd->set_pan_params)
		priv->cfg->ops->hcmd->set_pan_params(priv);

J
Johannes Berg 已提交
621
 out:
622
	mutex_unlock(&priv->mutex);
623 624
}

625 626
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
{
627
	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
628
	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
J
Johannes Berg 已提交
629
	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
630 631 632 633
	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
}
EXPORT_SYMBOL(iwl_setup_scan_deferred_work);