iwlwifi: mvm: wait for handlers when stopping scans

The recent unified scan api change introduced issues
when stopping ongoing scans, since both regular and
sched scan now use same stopped notification.

When issuing a new scan right after a running one,
we get the "old" notification and handle it wrongly
as notification for the current scan.

Fix it by introducing a new function that make sure
we consume the pending notifications before issuing
a new scan.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Reviewed-by: ArikX Nemtsov <arik@wizery.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This commit is contained in:
Eliad Peller 2014-06-22 18:15:59 +03:00 committed by Emmanuel Grumbach
parent 45bbb2ca1e
commit 4660dfbbe0
1 changed files with 51 additions and 35 deletions

View File

@ -1718,6 +1718,47 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
} }
static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
enum iwl_scan_status scan_type)
{
int ret;
bool wait_for_handlers = false;
mutex_lock(&mvm->mutex);
if (mvm->scan_status != scan_type) {
ret = 0;
/* make sure there are no pending notifications */
wait_for_handlers = true;
goto out;
}
switch (scan_type) {
case IWL_MVM_SCAN_SCHED:
ret = iwl_mvm_scan_offload_stop(mvm, true);
break;
case IWL_MVM_SCAN_OS:
ret = iwl_mvm_cancel_scan(mvm);
break;
case IWL_MVM_SCAN_NONE:
default:
WARN_ON_ONCE(1);
ret = -EINVAL;
break;
}
if (ret)
goto out;
wait_for_handlers = true;
out:
mutex_unlock(&mvm->mutex);
/* make sure we consume the completion notification */
if (wait_for_handlers)
iwl_mvm_wait_for_async_handlers(mvm);
return ret;
}
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req) struct ieee80211_scan_request *hw_req)
@ -1730,19 +1771,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
req->n_channels > mvm->fw->ucode_capa.n_scan_channels) req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
return -EINVAL; return -EINVAL;
ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
if (ret)
return ret;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
switch (mvm->scan_status) { if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
case IWL_MVM_SCAN_SCHED:
ret = iwl_mvm_scan_offload_stop(mvm, true);
if (ret) {
ret = -EBUSY;
goto out;
}
break;
case IWL_MVM_SCAN_NONE:
break;
default:
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
@ -1758,8 +1793,6 @@ 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;
} }
@ -2135,6 +2168,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret; int ret;
ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
if (ret)
return ret;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
if (!iwl_mvm_is_idle(mvm)) { if (!iwl_mvm_is_idle(mvm)) {
@ -2142,26 +2179,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
goto out; goto out;
} }
switch (mvm->scan_status) { if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
case IWL_MVM_SCAN_OS:
IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
ret = iwl_mvm_cancel_scan(mvm);
if (ret) {
ret = -EBUSY;
goto out;
}
/*
* iwl_mvm_rx_scan_complete() will be called soon but will
* not reset the scan status as it won't be IWL_MVM_SCAN_OS
* any more since we queue the next scan immediately (below).
* We make sure it is called before the next scan starts by
* flushing the async-handlers work.
*/
break;
case IWL_MVM_SCAN_NONE:
break;
default:
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
@ -2189,8 +2207,6 @@ err:
mvm->scan_status = IWL_MVM_SCAN_NONE; mvm->scan_status = IWL_MVM_SCAN_NONE;
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;
} }