iwlwifi: mvm: don't send BAR on flushed frames
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 6 Aug 2017 10:19:05 +0000 (13:19 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 18 Aug 2017 13:10:44 +0000 (16:10 +0300)
When we flush a queue, the packets will have a 'failed'
status but we shouldn't send a BAR. This check was missing.
Because of that, when we got an ampdu_action with
IEEE80211_AMPDU_TX_STOP_FLUSH, we started the following
ping pong with the firmware:

1) Set the station as 'draining'
2) Get a failed Tx status (DRAINED)
3) Send a BAR because of the failed Tx status

(loop of 2 and 3)

This loop wasn't endless since the BAR isn't sent on a
queue that would trigger a "nested" BAR.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index 48f028366d51b1186cb33001af03904b1503ab13..52f9e8a761249adc87ab3783768f4ce861ac2785 100644 (file)
@@ -1331,6 +1331,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
        while (!skb_queue_empty(&skbs)) {
                struct sk_buff *skb = __skb_dequeue(&skbs);
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+               bool flushed = false;
 
                skb_freed++;
 
@@ -1344,6 +1345,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                case TX_STATUS_DIRECT_DONE:
                        info->flags |= IEEE80211_TX_STAT_ACK;
                        break;
+               case TX_STATUS_FAIL_FIFO_FLUSHED:
+               case TX_STATUS_FAIL_DRAIN_FLOW:
+                       flushed = true;
+                       break;
                case TX_STATUS_FAIL_DEST_PS:
                        /* the FW should have stopped the queue and not
                         * return this status
@@ -1366,7 +1371,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                /* Single frame failure in an AMPDU queue => send BAR */
                if (info->flags & IEEE80211_TX_CTL_AMPDU &&
                    !(info->flags & IEEE80211_TX_STAT_ACK) &&
-                   !(info->flags & IEEE80211_TX_STAT_TX_FILTERED))
+                   !(info->flags & IEEE80211_TX_STAT_TX_FILTERED) && !flushed)
                        info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;