iwlwifi: mvm: fix AP/GO mode station removal

When stations are removed while packets are in the queue,
we drain the queues first, and then remove the stations.
If this happens in AP mode while the interface is removed
the MAC context might be removed from the firmware before
we removed the station(s), resulting in a SYSASSERT 3421.
This is because we remove the MAC context from the FW in
stop_ap(), but only flush the station drain work later in
remove_interface().

Refactor the code a bit to have a common MAC context
removal preparation first to solve this.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2013-02-22 14:07:56 +01:00
parent 8a964f44e0
commit 38a12b5b02

View File

@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
return ret; return ret;
} }
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 tfd_msk = 0, ac; u32 tfd_msk = 0, ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
*/ */
flush_work(&mvm->sta_drained_wk); flush_work(&mvm->sta_drained_wk);
} }
}
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_prepare_mac_removal(mvm, vif);
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
/* /*
* For AP/GO interface, the tear down of the resources allocated to the * For AP/GO interface, the tear down of the resources allocated to the
* interface should be handled as part of the bss_info_changed flow. * interface is be handled as part of the stop_ap flow.
*/ */
if (vif->type == NL80211_IFTYPE_AP) { if (vif->type == NL80211_IFTYPE_AP) {
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_prepare_mac_removal(mvm, vif);
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
mvmvif->ap_active = false; mvmvif->ap_active = false;