iwlwifi: mvm: wait for d0i3 exit in add interface flow
authorGregory Greenman <gregory.greenman@intel.com>
Wed, 25 Jun 2014 12:08:50 +0000 (14:08 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 6 Jul 2014 08:16:15 +0000 (11:16 +0300)
This patch makes sure there're no target accesses in the add
interface flow before d0i3 exit completes.

Signed-off-by: Gregory Greenman <gregory.greenman@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

index 5e425d3fddeb552b61b8a692954540b5cd321de7..7dde944a68fbe2f3bc5a69a52ab99dd892544d3e 100644 (file)
@@ -243,6 +243,21 @@ iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref)
        }
 }
 
+static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
+{
+       iwl_mvm_ref(mvm, ref_type);
+
+       if (!wait_event_timeout(mvm->d0i3_exit_waitq,
+                               !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status),
+                               HZ)) {
+               WARN_ON_ONCE(1);
+               iwl_mvm_unref(mvm, ref_type);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
 {
        int i;
@@ -559,9 +574,6 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
        case IEEE80211_AMPDU_TX_STOP_FLUSH:
        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG);
-               tx_agg_ref = true;
-
                /*
                 * for tx start, wait synchronously until D0i3 exit to
                 * get the correct sequence number for the tid.
@@ -570,12 +582,11 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                 * by the trans layer (unlike commands), so wait for
                 * d0i3 exit in these cases as well.
                 */
-               if (!wait_event_timeout(mvm->d0i3_exit_waitq,
-                         !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) {
-                       WARN_ON_ONCE(1);
-                       iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG);
-                       return -EIO;
-               }
+               ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_TX_AGG);
+               if (ret)
+                       return ret;
+
+               tx_agg_ref = true;
                break;
        default:
                break;
@@ -903,6 +914,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
 
+       /*
+        * make sure D0i3 exit is completed, otherwise a target access
+        * during tx queue configuration could be done when still in
+        * D0i3 state.
+        */
+       ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_ADD_IF);
+       if (ret)
+               return ret;
+
        /*
         * Not much to do here. The stack will not allow interface
         * types or combinations that we didn't advertise, so we
@@ -1017,6 +1037,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
  out_unlock:
        mutex_unlock(&mvm->mutex);
 
+       iwl_mvm_unref(mvm, IWL_MVM_REF_ADD_IF);
+
        return ret;
 }
 
index e067d9762603471c617567e0011886b698ba96a2..6fe93a7335c1d3548c4b84d327fbe0bc640fb09d 100644 (file)
@@ -230,6 +230,7 @@ enum iwl_mvm_ref_type {
        IWL_MVM_REF_USER,
        IWL_MVM_REF_TX,
        IWL_MVM_REF_TX_AGG,
+       IWL_MVM_REF_ADD_IF,
        IWL_MVM_REF_EXIT_WORK,
 
        IWL_MVM_REF_COUNT,