From: Abdurrahman Karadag <abdurrahmankaradag19@gmail.com>
To: pkshih@realtek.com
Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
rtl8821cerfe2@gmail.com,
Abdurrahman Karadag <abdurrahmankaradag19@gmail.com>
Subject: [PATCH rtw-next 1/2] wifi: rtw88: pci: wake the TX queues when the rings are reset
Date: Sat, 3 Oct 2026 02:10:12 +0300 [thread overview]
Message-ID: <20261002231013.11792-2-abdurrahmankaradag19@gmail.com> (raw)
In-Reply-To: <20261002231013.11792-1-abdurrahmankaradag19@gmail.com>
For a queue stopped by the PCI TX ring-full path, ring->queue_stopped
is normally cleared and the stop reason released only from the
completion loop in rtw_pci_tx_isr(). When the rings are reset the
pending descriptors are dropped and their skbs are freed directly by
rtw_pci_free_tx_ring_skbs(), so that loop never runs for them. The flag
and the stop reason both survive the reset, and because the ring is now
empty no completion will ever arrive to clear them. Any queue stopped
that way stays stopped.
This makes ieee80211_restart_hw() unable to recover a device that
stopped a queue before the restart, which is the opposite of what the
recovery is for.
Reproduced on an RTL8821CE by pausing TX in hardware, which freezes the
read index while the driver keeps submitting, the same shape the chip
shows when it wedges on its own:
# echo "522 f 1" > /sys/kernel/debug/ieee80211/phy0/rtw88/write_reg
# ... push traffic until the ring fills ...
BE 0x3a8: 0x0081007f, avail_desc() 1, BE queue stop reason 0x1
# (call rtw_fw_recovery() from a debug build)
firmware crash, start reset and recover
ieee80211 phy1: Hardware restart was requested
wlan0: associated
REG_TXPAUSE 0x00, BE 0x3a8: 0x00000000, ring empty
BE queue stop reason 0x1, 100% packet loss, no recovery in 90 s
The station reassociated twice during those 90 s, so the link was fine;
only the queue was still stopped. With this patch the same sequence
clears the stop reason and traffic returns within 2 s.
Record the queue mappings this path stops and release them both from
the completion loop and when the reset empties the ring. It has to be a
set rather than one value: the stop runs after every submission that
leaves fewer than two descriptors, rtw_pci_tx_write_data() still
accepts a frame while one is left, and rtw_tx_queue_mapping() places
management frames on the MGMT ring and multicast on HI0 whatever their
skb queue mapping is, so one ring can stop two different queues before
it is emptied. Keeping only the last one would leave the other stopped
for good.
Recording the mappings also limits the wake to the queues this
ring-full path actually stopped, instead of waking every mac80211
queue.
Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver")
Signed-off-by: Abdurrahman Karadag <abdurrahmankaradag19@gmail.com>
---
drivers/net/wireless/realtek/rtw88/pci.c | 45 ++++++++++++++++++++----
drivers/net/wireless/realtek/rtw88/pci.h | 1 +
2 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 66d2e5f..ff751bf 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -473,9 +473,41 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev)
BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX);
}
+static void rtw_pci_wake_stopped_queues(struct rtw_dev *rtwdev,
+ struct rtw_pci_tx_ring *ring)
+{
+ unsigned long q;
+
+ for_each_set_bit(q, &ring->stopped_queues, rtwdev->hw->queues)
+ ieee80211_wake_queue(rtwdev->hw, q);
+
+ ring->stopped_queues = 0;
+ ring->queue_stopped = false;
+}
+
static void rtw_pci_reset_trx_ring(struct rtw_dev *rtwdev)
{
+ struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct rtw_pci_tx_ring *ring;
+ enum rtw_tx_queue_type queue;
+
rtw_pci_reset_buf_desc(rtwdev);
+
+ /*
+ * The rings are empty again, so nothing is left whose completion
+ * could reach the wake in rtw_pci_tx_isr(). Release the queues this
+ * path stopped - the stop reasons it set are cleared nowhere else,
+ * and over an empty ring no completion will ever arrive to clear
+ * them.
+ */
+ for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
+ ring = &rtwpci->tx_rings[queue];
+
+ if (!ring->queue_stopped)
+ continue;
+
+ rtw_pci_wake_stopped_queues(rtwdev, ring);
+ }
}
static void rtw_pci_enable_interrupt(struct rtw_dev *rtwdev,
@@ -930,7 +962,10 @@ static int rtw_pci_tx_write(struct rtw_dev *rtwdev,
ring = &rtwpci->tx_rings[queue];
spin_lock_bh(&rtwpci->irq_lock);
if (avail_desc(ring->r.wp, ring->r.rp, ring->r.len) < 2) {
- ieee80211_stop_queue(rtwdev->hw, skb_get_queue_mapping(skb));
+ u16 q_map = skb_get_queue_mapping(skb);
+
+ ieee80211_stop_queue(rtwdev->hw, q_map);
+ set_bit(q_map, &ring->stopped_queues);
ring->queue_stopped = true;
}
spin_unlock_bh(&rtwpci->irq_lock);
@@ -949,7 +984,6 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
u32 count;
u32 bd_idx_addr;
u32 bd_idx, cur_rp, rp_idx;
- u16 q_map;
ring = &rtwpci->tx_rings[hw_queue];
@@ -981,11 +1015,8 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
}
if (ring->queue_stopped &&
- avail_desc(ring->r.wp, rp_idx, ring->r.len) > 4) {
- q_map = skb_get_queue_mapping(skb);
- ieee80211_wake_queue(hw, q_map);
- ring->queue_stopped = false;
- }
+ avail_desc(ring->r.wp, rp_idx, ring->r.len) > 4)
+ rtw_pci_wake_stopped_queues(rtwdev, ring);
if (++rp_idx >= ring->r.len)
rp_idx = 0;
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index 8ffdea1..04630d1 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -188,6 +188,7 @@ struct rtw_pci_tx_ring {
struct rtw_pci_ring r;
struct sk_buff_head queue;
bool queue_stopped;
+ unsigned long stopped_queues;
};
struct rtw_pci_rx_buffer_desc {
--
2.55.0
next prev parent reply other threads:[~2026-10-02 23:10 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 23:10 [PATCH rtw-next 0/2] rtw88: recover a stopped TX queue, and notice a stalled ring Abdurrahman Karadag
2026-10-02 23:10 ` Abdurrahman Karadag [this message]
2026-10-02 23:10 ` [PATCH rtw-next 2/2] wifi: rtw88: pci: warn when a TX ring stops advancing Abdurrahman Karadag
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261002231013.11792-2-abdurrahmankaradag19@gmail.com \
--to=abdurrahmankaradag19@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=pkshih@realtek.com \
--cc=rtl8821cerfe2@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®