summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/mvm
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-02-10 17:34:29 +0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-03-09 21:16:48 +0400
commit33ea27f66afa9ca3e130bd00c595dca509152fd7 (patch)
tree6fd5a2d075e9aaef96638d4d8b04c2508100f5d8 /drivers/net/wireless/iwlwifi/mvm
parent7bb426ea36f143459895de0cf11f0f0a7cfa396a (diff)
downloadlinux-33ea27f66afa9ca3e130bd00c595dca509152fd7.tar.xz
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: Arik Nemtsov <arikx.nemtsov@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c24
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c42
3 files changed, 46 insertions, 27 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 41b9e65f6a3f..fff66ab2cfda 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -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,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 3511bf79abcd..4da53c395ad3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -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);
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index b4c9fb649976..a2cd54b57e67 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -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);
+ 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_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
+ 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;
}