Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b856439b authored by Eliad Peller's avatar Eliad Peller Committed by John W. Linville
Browse files

mac80211: add cancel_hw_scan() callback



When suspending, __ieee80211_suspend() calls ieee80211_scan_cancel(),
which will only cancel sw scan. In order to cancel hw scan, the
low-level driver has to cancel it in the suspend() callback. however,
this is too late, as a new scan_work will be enqueued (while the driver
is going into suspend).

Add a new cancel_hw_scan() callback, asking the driver to cancel an
active hw scan, and call it in ieee80211_scan_cancel().

Signed-off-by: default avatarEliad Peller <eliad@wizery.com>
Reviewed-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent eb40e3e8
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1708,6 +1708,14 @@ enum ieee80211_ampdu_mlme_action {
 *	any error unless this callback returned a negative error code.
 *	The callback can sleep.
 *
 * @cancel_hw_scan: Ask the low-level tp cancel the active hw scan.
 *	The driver should ask the hardware to cancel the scan (if possible),
 *	but the scan will be completed only after the driver will call
 *	ieee80211_scan_completed().
 *	This callback is needed for wowlan, to prevent enqueueing a new
 *	scan_work after the low-level driver was already suspended.
 *	The callback can sleep.
 *
 * @sched_scan_start: Ask the hardware to start scanning repeatedly at
 *	specific intervals.  The driver must call the
 *	ieee80211_sched_scan_results() function whenever it finds results.
@@ -1900,6 +1908,8 @@ struct ieee80211_ops {
				u32 iv32, u16 *phase1key);
	int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		       struct cfg80211_scan_request *req);
	void (*cancel_hw_scan)(struct ieee80211_hw *hw,
			       struct ieee80211_vif *vif);
	int (*sched_scan_start)(struct ieee80211_hw *hw,
				struct ieee80211_vif *vif,
				struct cfg80211_sched_scan_request *req,
+10 −0
Original line number Diff line number Diff line
@@ -218,6 +218,16 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
	return ret;
}

static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
				      struct ieee80211_sub_if_data *sdata)
{
	might_sleep();

	trace_drv_cancel_hw_scan(local, sdata);
	local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
	trace_drv_return_void(local);
}

static inline int
drv_sched_scan_start(struct ieee80211_local *local,
		     struct ieee80211_sub_if_data *sdata,
+6 −0
Original line number Diff line number Diff line
@@ -460,6 +460,12 @@ DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
	TP_ARGS(local, sdata)
);

DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
	TP_PROTO(struct ieee80211_local *local,
		 struct ieee80211_sub_if_data *sdata),
	TP_ARGS(local, sdata)
);

DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
	TP_PROTO(struct ieee80211_local *local,
		 struct ieee80211_sub_if_data *sdata),
+21 −16
Original line number Diff line number Diff line
@@ -821,10 +821,8 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 */
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
	bool abortscan;

	/*
	 * We are only canceling software scan, or deferred scan that was not
	 * We are canceling software scan, or deferred scan that was not
	 * yet really started (see __ieee80211_start_scan ).
	 *
	 * Regarding hardware scan:
@@ -836,15 +834,22 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
	 * - we can not cancel scan_work since driver can schedule it
	 *   by ieee80211_scan_completed(..., true) to finish scan
	 *
	 * Hence low lever driver is responsible for canceling HW scan.
	 * Hence we only call the cancel_hw_scan() callback, but the low-level
	 * driver is still responsible for calling ieee80211_scan_completed()
	 * after the scan was completed/aborted.
	 */

	mutex_lock(&local->mtx);
	abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
	if (abortscan) {
	if (!local->scan_req)
		goto out;

	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
		if (local->ops->cancel_hw_scan)
			drv_cancel_hw_scan(local, local->scan_sdata);
		goto out;
	}

	/*
		 * The scan is canceled, but stop work from being pending.
		 *
	 * If the work is currently running, it must be blocked on
	 * the mutex, but we'll set scan_sdata = NULL and it'll
	 * simply exit once it acquires the mutex.
@@ -852,7 +857,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
	cancel_delayed_work(&local->scan_work);
	/* and clean up */
	__ieee80211_scan_completed(&local->hw, true, false);
	}
out:
	mutex_unlock(&local->mtx);
}