Return-path: Received: from mail-ee0-f45.google.com ([74.125.83.45]:42102 "EHLO mail-ee0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755966AbaCROqD (ORCPT ); Tue, 18 Mar 2014 10:46:03 -0400 Received: by mail-ee0-f45.google.com with SMTP id d17so5404854eek.18 for ; Tue, 18 Mar 2014 07:46:01 -0700 (PDT) From: Emmanuel Grumbach To: linux-wireless@vger.kernel.org Cc: Arik Nemtsov , Arik Nemtsov , Emmanuel Grumbach Subject: [PATCH 11/35] iwlwifi: mvm: wait for stop sched-scan completion Date: Tue, 18 Mar 2014 16:45:15 +0200 Message-Id: <1395153939-23897-11-git-send-email-egrumbach@gmail.com> (sfid-20140318_154610_178707_D669592F) In-Reply-To: <53285AF8.7050305@gmail.com> References: <53285AF8.7050305@gmail.com> Sender: linux-wireless-owner@vger.kernel.org List-ID: From: Arik Nemtsov 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 Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 24 +++++------------ drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 ++++- drivers/net/wireless/iwlwifi/mvm/scan.c | 42 ++++++++++++++++++++++------- 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 41b9e65..fff66ab 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 3511bf7..4da53c3 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 b4c9fb6..a2cd54b 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; } -- 1.8.3.2