]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: empty overflow queue during flush
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Sun, 22 Oct 2023 14:55:51 +0000 (17:55 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:08:16 +0000 (11:08 +0100)
[ Upstream commit 658939fc68d3241f9a0019e224cd7154438c23f2 ]

If a TX queue has no space for new TX frames, the driver will keep
these frames in the overflow queue, and during reclaim flow it
will retry to send the frames from that queue.
But if the reclaim flow was invoked from TX queue flush, we will also
TX these frames, which is wrong as we don't want to TX anything
after flush.
This might also cause assert 0x125F when removing the queue,
saying that the driver removes a non-empty queue
Fix this by TXing the overflow queue's frames only if we are
not in flush queue flow.

Fixes: a44509805895 ("iwlwifi: move reclaim flows to the queue file")
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20231022173519.caf06c8709d9.Ibf664ccb3f952e836f8fa461ea58fc08e5c46e88@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/intel/iwlwifi/dvm/tx.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/queue/tx.c
drivers/net/wireless/intel/iwlwifi/queue/tx.h

index 847b8e07f81c517b34a0892667e520002ce0281c..a6999ca75377c9f62e9e22fade157d46b35826ad 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2023 Intel Corporation
  *
  * Contact Information:
  *  Intel Linux Wireless <linuxwifi@intel.com>
@@ -1174,7 +1175,7 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)
                        iwlagn_check_ratid_empty(priv, sta_id, tid);
                }
 
-               iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
+               iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs, false);
 
                freed = 0;
 
@@ -1320,7 +1321,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
         * block-ack window (we assume that they've been successfully
         * transmitted ... if not, it's too late anyway). */
        iwl_trans_reclaim(priv->trans, scd_flow, ba_resp_scd_ssn,
-                         &reclaimed_skbs);
+                         &reclaimed_skbs, false);
 
        IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
                           "sta_id = %d\n",
index 8f0ff540f4398e6776a9bb6fe132047899a4f0a8..a2919a32d7081b4864de4aa3189bcb9f118ddede 100644 (file)
@@ -539,7 +539,7 @@ struct iwl_trans_ops {
        int (*tx)(struct iwl_trans *trans, struct sk_buff *skb,
                  struct iwl_device_tx_cmd *dev_cmd, int queue);
        void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
-                       struct sk_buff_head *skbs);
+                       struct sk_buff_head *skbs, bool is_flush);
 
        void (*set_q_ptrs)(struct iwl_trans *trans, int queue, int ptr);
 
@@ -1122,14 +1122,15 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
 }
 
 static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
-                                    int ssn, struct sk_buff_head *skbs)
+                                    int ssn, struct sk_buff_head *skbs,
+                                    bool is_flush)
 {
        if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
                return;
        }
 
-       trans->ops->reclaim(trans, queue, ssn, skbs);
+       trans->ops->reclaim(trans, queue, ssn, skbs, is_flush);
 }
 
 static inline void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue,
index b127e0b527ce026ebd5dd78b37d6bac1682dcce2..4375da00f7cf0550533dc1b9f75e82acc3a76fd7 100644 (file)
@@ -1432,7 +1432,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
        seq_ctl = le16_to_cpu(tx_resp->seq_ctl);
 
        /* we can free until ssn % q.n_bd not inclusive */
-       iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs);
+       iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs, false);
 
        while (!skb_queue_empty(&skbs)) {
                struct sk_buff *skb = __skb_dequeue(&skbs);
@@ -1777,7 +1777,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
         * block-ack window (we assume that they've been successfully
         * transmitted ... if not, it's too late anyway).
         */
-       iwl_trans_reclaim(mvm->trans, txq, index, &reclaimed_skbs);
+       iwl_trans_reclaim(mvm->trans, txq, index, &reclaimed_skbs, is_flush);
 
        skb_queue_walk(&reclaimed_skbs, skb) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
index 8522cdfc9e5d306a95b26955f8ec72f23c3b32e8..cd852b95d8125845e3df4c9bc7f1dbcb3913ed87 100644 (file)
@@ -1520,7 +1520,7 @@ void iwl_txq_progress(struct iwl_txq *txq)
 
 /* Frees buffers until index _not_ inclusive */
 void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
-                    struct sk_buff_head *skbs)
+                    struct sk_buff_head *skbs, bool is_flush)
 {
        struct iwl_txq *txq = trans->txqs.txq[txq_id];
        int tfd_num = iwl_txq_get_cmd_index(txq, ssn);
@@ -1591,9 +1591,11 @@ void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
        if (iwl_txq_space(trans, txq) > txq->low_mark &&
            test_bit(txq_id, trans->txqs.queue_stopped)) {
                struct sk_buff_head overflow_skbs;
+               struct sk_buff *skb;
 
                __skb_queue_head_init(&overflow_skbs);
-               skb_queue_splice_init(&txq->overflow_q, &overflow_skbs);
+               skb_queue_splice_init(&txq->overflow_q,
+                                     is_flush ? skbs : &overflow_skbs);
 
                /*
                 * We are going to transmit from the overflow queue.
@@ -1613,8 +1615,7 @@ void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
                 */
                spin_unlock_bh(&txq->lock);
 
-               while (!skb_queue_empty(&overflow_skbs)) {
-                       struct sk_buff *skb = __skb_dequeue(&overflow_skbs);
+               while ((skb = __skb_dequeue(&overflow_skbs))) {
                        struct iwl_device_tx_cmd *dev_cmd_ptr;
 
                        dev_cmd_ptr = *(void **)((u8 *)skb->cb +
index 19178c88bb229829a1e02b8e54c530361036889b..f488fc9f6b83e2dee9969fafb63ad26baff13f64 100644 (file)
@@ -174,7 +174,7 @@ void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans,
                                      struct iwl_txq *txq, u16 byte_cnt,
                                      int num_tbs);
 void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
-                    struct sk_buff_head *skbs);
+                    struct sk_buff_head *skbs, bool is_flush);
 void iwl_txq_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr);
 void iwl_trans_txq_freeze_timer(struct iwl_trans *trans, unsigned long txqs,
                                bool freeze);