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

Commit 33ea27f6 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Emmanuel Grumbach
Browse files

iwlwifi: mvm: wait for stop sched-scan completion



cfg80211 assumes a scheduled scan is stopped synchronously. Wait for the
FW before returning to caller.

Don't do anything in the async handler in the stop-from-above flow.
There's no need to call the mac80211 sched-scan completion as the
cleanup will be automatic. Make sure the async handler is called before
the next incoming scan changes the scan_status by flushing the async
handlers after all invocations.

Signed-off-by: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 7bb426ea
Loading
Loading
Loading
Loading
+7 −17
Original line number Diff line number Diff line
@@ -1419,8 +1419,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
			       struct cfg80211_scan_request *req)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_notification_wait wait_scan_done;
	static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
	int ret;

	if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS)
@@ -1430,22 +1428,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,

	switch (mvm->scan_status) {
	case IWL_MVM_SCAN_SCHED:
		iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
					   scan_done_notif,
					   ARRAY_SIZE(scan_done_notif),
					   NULL, NULL);
		iwl_mvm_sched_scan_stop(mvm);
		ret = iwl_wait_notification(&mvm->notif_wait,
					    &wait_scan_done, HZ);
		ret = iwl_mvm_sched_scan_stop(mvm);
		if (ret) {
			ret = -EBUSY;
			goto out;
		}
		/* iwl_mvm_rx_scan_offload_complete_notif() will be called
		 * soon but will not reset the scan status as it won't be
		 * IWL_MVM_SCAN_SCHED any more since we queue the next scan
		 * immediately (below)
		 */
		break;
	case IWL_MVM_SCAN_NONE:
		break;
@@ -1461,7 +1448,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
		iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
out:
	mutex_unlock(&mvm->mutex);

	/* make sure to flush the Rx handler before the next scan arrives */
	iwl_mvm_wait_for_async_handlers(mvm);
	return ret;
}

@@ -1751,12 +1739,14 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	int ret;

	mutex_lock(&mvm->mutex);
	iwl_mvm_sched_scan_stop(mvm);
	ret = iwl_mvm_sched_scan_stop(mvm);
	mutex_unlock(&mvm->mutex);
	iwl_mvm_wait_for_async_handlers(mvm);

	return 0;
	return ret;
}

static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+6 −1
Original line number Diff line number Diff line
@@ -712,6 +712,11 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);

static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)
{
	flush_work(&mvm->async_handlers_wk);
}

/* Statistics */
int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
				struct iwl_rx_cmd_buffer *rxb,
@@ -813,7 +818,7 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
				       struct cfg80211_sched_scan_request *req);
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
			     struct cfg80211_sched_scan_request *req);
void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
				  struct iwl_rx_cmd_buffer *rxb,
				  struct iwl_device_cmd *cmd);
+33 −9
Original line number Diff line number Diff line
@@ -519,10 +519,11 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
		       scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
		       "completed" : "aborted");

	/* might already be something else again, don't reset if so */
	if (mvm->scan_status == IWL_MVM_SCAN_SCHED)
	/* only call mac80211 completion if the stop was initiated by FW */
	if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
		mvm->scan_status = IWL_MVM_SCAN_NONE;
		ieee80211_sched_scan_stopped(mvm->hw);
	}

	return 0;
}
@@ -894,26 +895,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
		 * microcode has notified us that a scan is completed.
		 */
		IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
		ret = -EIO;
		ret = -ENOENT;
	}

	return ret;
}

void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
{
	int ret;
	struct iwl_notification_wait wait_scan_done;
	static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };

	lockdep_assert_held(&mvm->mutex);

	if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
		IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
		return;
		return 0;
	}

	iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
				   scan_done_notif,
				   ARRAY_SIZE(scan_done_notif),
				   NULL, NULL);

	ret = iwl_mvm_send_sched_scan_abort(mvm);
	if (ret)
	if (ret) {
		IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
	else
		iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
		return ret;
	}

	IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");

	ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
	if (ret)
		return ret;

	/*
	 * Clear the scan status so the next scan requests will succeed. This
	 * also ensures the Rx handler doesn't do anything, as the scan was
	 * stopped from above.
	 */
	mvm->scan_status = IWL_MVM_SCAN_NONE;

	return 0;
}