diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tx.c | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 479074303bd7..f212f16502ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
416 | 416 | ||
417 | spin_unlock(&mvmsta->lock); | 417 | spin_unlock(&mvmsta->lock); |
418 | 418 | ||
419 | if (mvmsta->vif->type == NL80211_IFTYPE_AP && | 419 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE) |
420 | txq_id < IWL_MVM_FIRST_AGG_QUEUE) | 420 | atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); |
421 | atomic_inc(&mvmsta->pending_frames); | ||
422 | 421 | ||
423 | return 0; | 422 | return 0; |
424 | 423 | ||
@@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
680 | /* | 679 | /* |
681 | * If the txq is not an AMPDU queue, there is no chance we freed | 680 | * If the txq is not an AMPDU queue, there is no chance we freed |
682 | * several skbs. Check that out... | 681 | * several skbs. Check that out... |
683 | * If there are no pending frames for this STA, notify mac80211 that | ||
684 | * this station can go to sleep in its STA table. | ||
685 | */ | 682 | */ |
686 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && | 683 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) && |
687 | !WARN_ON(skb_freed > 1) && | 684 | atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { |
688 | mvmsta->vif->type == NL80211_IFTYPE_AP && | 685 | if (mvmsta) { |
689 | atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { | 686 | /* |
690 | ieee80211_sta_block_awake(mvm->hw, sta, false); | 687 | * If there are no pending frames for this STA, notify |
691 | set_bit(sta_id, mvm->sta_drained); | 688 | * mac80211 that this station can go to sleep in its |
692 | schedule_work(&mvm->sta_drained_wk); | 689 | * STA table. |
690 | */ | ||
691 | if (mvmsta->vif->type == NL80211_IFTYPE_AP) | ||
692 | ieee80211_sta_block_awake(mvm->hw, sta, false); | ||
693 | /* | ||
694 | * We might very well have taken mvmsta pointer while | ||
695 | * the station was being removed. The remove flow might | ||
696 | * have seen a pending_frame (because we didn't take | ||
697 | * the lock) even if now the queues are drained. So make | ||
698 | * really sure now that this the station is not being | ||
699 | * removed. If it is, run the drain worker to remove it. | ||
700 | */ | ||
701 | spin_lock_bh(&mvmsta->lock); | ||
702 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
703 | if (IS_ERR_OR_NULL(sta)) { | ||
704 | /* | ||
705 | * Station disappeared in the meantime: | ||
706 | * so we are draining. | ||
707 | */ | ||
708 | set_bit(sta_id, mvm->sta_drained); | ||
709 | schedule_work(&mvm->sta_drained_wk); | ||
710 | } | ||
711 | spin_unlock_bh(&mvmsta->lock); | ||
712 | } else if (!mvmsta) { | ||
713 | /* Tx response without STA, so we are draining */ | ||
714 | set_bit(sta_id, mvm->sta_drained); | ||
715 | schedule_work(&mvm->sta_drained_wk); | ||
716 | } | ||
693 | } | 717 | } |
694 | 718 | ||
695 | rcu_read_unlock(); | 719 | rcu_read_unlock(); |