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 Original line 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 cfg80211_scan_request *req)
{
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	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;
	int ret;


	if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS)
	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) {
	switch (mvm->scan_status) {
	case IWL_MVM_SCAN_SCHED:
	case IWL_MVM_SCAN_SCHED:
		iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
		ret = iwl_mvm_sched_scan_stop(mvm);
					   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);
		if (ret) {
		if (ret) {
			ret = -EBUSY;
			ret = -EBUSY;
			goto out;
			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;
		break;
	case IWL_MVM_SCAN_NONE:
	case IWL_MVM_SCAN_NONE:
		break;
		break;
@@ -1461,7 +1448,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
		iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
		iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
out:
out:
	mutex_unlock(&mvm->mutex);
	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;
	return ret;
}
}


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


	mutex_lock(&mvm->mutex);
	mutex_lock(&mvm->mutex);
	iwl_mvm_sched_scan_stop(mvm);
	ret = iwl_mvm_sched_scan_stop(mvm);
	mutex_unlock(&mvm->mutex);
	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,
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+6 −1
Original line number Original line 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);
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);
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 */
/* Statistics */
int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
				struct iwl_rx_cmd_buffer *rxb,
				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);
				       struct cfg80211_sched_scan_request *req);
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
			     struct cfg80211_sched_scan_request *req);
			     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,
int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
				  struct iwl_rx_cmd_buffer *rxb,
				  struct iwl_rx_cmd_buffer *rxb,
				  struct iwl_device_cmd *cmd);
				  struct iwl_device_cmd *cmd);
+33 −9
Original line number Original line 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 ?
		       scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
		       "completed" : "aborted");
		       "completed" : "aborted");


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


	return 0;
	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.
		 * microcode has notified us that a scan is completed.
		 */
		 */
		IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
		IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
		ret = -EIO;
		ret = -ENOENT;
	}
	}


	return ret;
	return ret;
}
}


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


	lockdep_assert_held(&mvm->mutex);
	lockdep_assert_held(&mvm->mutex);


	if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
	if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
		IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
		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);
	ret = iwl_mvm_send_sched_scan_abort(mvm);
	if (ret)
	if (ret) {
		IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", 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");
	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;
}
}