iwlwifi: mvm: wait for stop sched-scan completion
authorArik Nemtsov <arik@wizery.com>
Mon, 10 Feb 2014 13:34:29 +0000 (15:34 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 9 Mar 2014 17:16:48 +0000 (19:16 +0200)
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>
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/scan.c

index 41b9e65f6a3f7b7a0a15773bc69b7aef67089922..fff66ab2cfda0eb304a5a55418b7451bd96143fc 100644 (file)
@@ -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,
index 3511bf79abcdc19bcfaa9b7f43de40e958946b17..4da53c395ad306f00de3f5f1af77fac1e92bd3a9 100644 (file)
@@ -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);
index b4c9fb64997619c6c315eb4d824ca56ebfd04bc7..a2cd54b57e678b68471c5b8277b573445b4543b4 100644 (file)
@@ -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;
 }