aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2014-07-01 11:38:38 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-07-21 03:43:13 -0400
commit576eeee9d3ab395f47462c03067c8b9381281f1d (patch)
treed8511410c9fcdb97ad4b06790b63d77f0c08bfbf /drivers/net/wireless/iwlwifi/mvm/mac80211.c
parent51ea1c7dbd4c5151b7f5777cabc505d43d2c42cb (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.c66
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
228static void 232static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm,
229iwl_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
246static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) 254int 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);
1595out_unlock: 1611out_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
1695static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, 1721static 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
2074static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, 2109static 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
2086static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, 2130static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,