summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-12-04 22:39:17 +0100
committerJohannes Berg <johannes.berg@intel.com>2013-12-16 11:29:44 +0100
commit1ddbbb0c83de82599b1baf14bf6bb69a774d4fc7 (patch)
treef40e872724a1d8a4de63f75e2e7d357adacc99a8 /drivers/net/wireless/iwlwifi/mvm/mac80211.c
parent6a9d1b91f34df1935bc0ad98114801a44db0f98c (diff)
downloadlinux-1ddbbb0c83de82599b1baf14bf6bb69a774d4fc7.tar.bz2
iwlwifi: mvm: use pre-RCU-sync sta removal operation
iwlmvm relies on the current mac80211 behaviour of allowing station pointers to be valid for an RCU grace period after returning from the sta_state() callback. To optimise these cases, this behaviour is going away, so make the driver use the new sta_pre_rcu_remove() method to clear the pointer in the fw_id_to_mac_id[] array. Since this may happen while the station is still present in the firmware, don't set the pointer to NULL but to -ENOENT to mark this particular case. In client mode, the station is kept even longer (until marking the MAC as unassociated) so the drain flow must take this new behavior into account. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index afc4419be46d..a77007cfd765 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1114,6 +1114,28 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
}
}
+static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+ /*
+ * This is called before mac80211 does RCU synchronisation,
+ * so here we already invalidate our internal RCU-protected
+ * station pointer. The rest of the code will thus no longer
+ * be able to find the station this way, and we don't rely
+ * on further RCU synchronisation after the sta_state()
+ * callback deleted the station.
+ */
+ mutex_lock(&mvm->mutex);
+ if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id]))
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+ ERR_PTR(-ENOENT));
+ mutex_unlock(&mvm->mutex);
+}
+
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -1761,6 +1783,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.bss_info_changed = iwl_mvm_bss_info_changed,
.hw_scan = iwl_mvm_mac_hw_scan,
.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
+ .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
.sta_state = iwl_mvm_mac_sta_state,
.sta_notify = iwl_mvm_mac_sta_notify,
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,