diff options
author | Eliad Peller <eliad@wizery.com> | 2014-07-01 11:38:38 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-07-21 03:43:13 -0400 |
commit | 576eeee9d3ab395f47462c03067c8b9381281f1d (patch) | |
tree | d8511410c9fcdb97ad4b06790b63d77f0c08bfbf /drivers/net/wireless/iwlwifi/mvm/mac80211.c | |
parent | 51ea1c7dbd4c5151b7f5777cabc505d43d2c42cb (diff) |
iwlwifi: mvm: add some missing iwl_mvm_ref_sync() calls
Add iwl_mvm_ref_sync() calls (with new ref types) to
flows that might access the device directly.
These calls make sure the device is out of d0i3,
and the bus is available for direct access.
Since some of these functions are reentrant, convert
the refs_bitmap to a ref counter, so multiple refs
of the same type could be taken concurrently.
Signed-off-by: Eliad Peller <eliadx.peller@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2eb6ebee4467..12a9aed7a5d3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | |||
211 | return; | 211 | return; |
212 | 212 | ||
213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); | 213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); |
214 | WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); | 214 | spin_lock_bh(&mvm->refs_lock); |
215 | mvm->refs[ref_type]++; | ||
216 | spin_unlock_bh(&mvm->refs_lock); | ||
215 | iwl_trans_ref(mvm->trans); | 217 | iwl_trans_ref(mvm->trans); |
216 | } | 218 | } |
217 | 219 | ||
@@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | |||
221 | return; | 223 | return; |
222 | 224 | ||
223 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); | 225 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); |
224 | WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); | 226 | spin_lock_bh(&mvm->refs_lock); |
227 | WARN_ON(!mvm->refs[ref_type]--); | ||
228 | spin_unlock_bh(&mvm->refs_lock); | ||
225 | iwl_trans_unref(mvm->trans); | 229 | iwl_trans_unref(mvm->trans); |
226 | } | 230 | } |
227 | 231 | ||
228 | static void | 232 | static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, |
229 | iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) | 233 | enum iwl_mvm_ref_type except_ref) |
230 | { | 234 | { |
231 | int i; | 235 | int i, j; |
232 | 236 | ||
233 | if (!iwl_mvm_is_d0i3_supported(mvm)) | 237 | if (!iwl_mvm_is_d0i3_supported(mvm)) |
234 | return; | 238 | return; |
235 | 239 | ||
236 | for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { | 240 | spin_lock_bh(&mvm->refs_lock); |
237 | if (ref == i) | 241 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { |
242 | if (except_ref == i || !mvm->refs[i]) | ||
238 | continue; | 243 | continue; |
239 | 244 | ||
240 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); | 245 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n", |
241 | clear_bit(i, mvm->ref_bitmap); | 246 | i, mvm->refs[i]); |
242 | iwl_trans_unref(mvm->trans); | 247 | for (j = 0; j < mvm->refs[i]; j++) |
248 | iwl_trans_unref(mvm->trans); | ||
249 | mvm->refs[i] = 0; | ||
243 | } | 250 | } |
251 | spin_unlock_bh(&mvm->refs_lock); | ||
244 | } | 252 | } |
245 | 253 | ||
246 | static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 254 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
247 | { | 255 | { |
248 | iwl_mvm_ref(mvm, ref_type); | 256 | iwl_mvm_ref(mvm, ref_type); |
249 | 257 | ||
@@ -1533,6 +1541,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1533 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1541 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1534 | int ret; | 1542 | int ret; |
1535 | 1543 | ||
1544 | /* | ||
1545 | * iwl_mvm_mac_ctxt_add() might read directly from the device | ||
1546 | * (the system time), so make sure it is available. | ||
1547 | */ | ||
1548 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP); | ||
1549 | if (ret) | ||
1550 | return ret; | ||
1551 | |||
1536 | mutex_lock(&mvm->mutex); | 1552 | mutex_lock(&mvm->mutex); |
1537 | 1553 | ||
1538 | /* Send the beacon template */ | 1554 | /* Send the beacon template */ |
@@ -1594,6 +1610,7 @@ out_remove: | |||
1594 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1610 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1595 | out_unlock: | 1611 | out_unlock: |
1596 | mutex_unlock(&mvm->mutex); | 1612 | mutex_unlock(&mvm->mutex); |
1613 | iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP); | ||
1597 | return ret; | 1614 | return ret; |
1598 | } | 1615 | } |
1599 | 1616 | ||
@@ -1671,6 +1688,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
1671 | { | 1688 | { |
1672 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1689 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1673 | 1690 | ||
1691 | /* | ||
1692 | * iwl_mvm_bss_info_changed_station() might call | ||
1693 | * iwl_mvm_protect_session(), which reads directly from | ||
1694 | * the device (the system time), so make sure it is available. | ||
1695 | */ | ||
1696 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED)) | ||
1697 | return; | ||
1698 | |||
1674 | mutex_lock(&mvm->mutex); | 1699 | mutex_lock(&mvm->mutex); |
1675 | 1700 | ||
1676 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) | 1701 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) |
@@ -1690,6 +1715,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
1690 | } | 1715 | } |
1691 | 1716 | ||
1692 | mutex_unlock(&mvm->mutex); | 1717 | mutex_unlock(&mvm->mutex); |
1718 | iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); | ||
1693 | } | 1719 | } |
1694 | 1720 | ||
1695 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | 1721 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, |
@@ -2065,10 +2091,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
2065 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) | 2091 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) |
2066 | return; | 2092 | return; |
2067 | 2093 | ||
2094 | /* | ||
2095 | * iwl_mvm_protect_session() reads directly from the device | ||
2096 | * (the system time), so make sure it is available. | ||
2097 | */ | ||
2098 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) | ||
2099 | return; | ||
2100 | |||
2068 | mutex_lock(&mvm->mutex); | 2101 | mutex_lock(&mvm->mutex); |
2069 | /* Try really hard to protect the session and hear a beacon */ | 2102 | /* Try really hard to protect the session and hear a beacon */ |
2070 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); | 2103 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); |
2071 | mutex_unlock(&mvm->mutex); | 2104 | mutex_unlock(&mvm->mutex); |
2105 | |||
2106 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); | ||
2072 | } | 2107 | } |
2073 | 2108 | ||
2074 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | 2109 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, |
@@ -2077,10 +2112,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | |||
2077 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2112 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2078 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; | 2113 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; |
2079 | 2114 | ||
2115 | /* | ||
2116 | * iwl_mvm_protect_session() reads directly from the device | ||
2117 | * (the system time), so make sure it is available. | ||
2118 | */ | ||
2119 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) | ||
2120 | return; | ||
2121 | |||
2080 | mutex_lock(&mvm->mutex); | 2122 | mutex_lock(&mvm->mutex); |
2081 | /* Protect the session to hear the TDLS setup response on the channel */ | 2123 | /* Protect the session to hear the TDLS setup response on the channel */ |
2082 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); | 2124 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); |
2083 | mutex_unlock(&mvm->mutex); | 2125 | mutex_unlock(&mvm->mutex); |
2126 | |||
2127 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | ||
2084 | } | 2128 | } |
2085 | 2129 | ||
2086 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | 2130 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, |