Re: [PATCH net 1/2] net: macb: reprogram TBQP after shuffling the TX ring on link-up
From: Taedcke, Christian <hidden>
Date: 2026-07-14 15:35:58
Also in:
linux-rt-devel, lkml, stable
Hello Kevin & Théo, i recorded some traces and include 2 of them here. On 7/10/2026 3:56 PM, Théo Lebrun wrote:
Hello Kevin & Christian, On Wed Jul 8, 2026 at 5:05 AM CEST, Kevin Hao wrote:quoted
quoted
I agree that the TRM says the transmit pointer is reset while TE is low. My question is whether this describes an internal pointer being reloaded from TBQP, or whether TBQP itself is restored to the original ring base.The Zynq UltraScale TRM [1] describes the receive-buffer queue pointer as follows: An internal counter represents the receive-buffer queue pointer and it is not visible through the CPU interface. I could not find a similar description for the transmit-buffer queue pointer, but I believe it behaves the same way. From a software perspective, it should be safe to assume that the TBQP is reset to point to the start of the transmit descriptor list upon reset. This assumption is supported by the description of the transmit_q_ptr (GEM) Register [2]: Reading this register returns the location of the descriptor currently being accessed. Since the DMA handles two frames at once, this may not necessarily be pointing to the current frame being transmitted. [1] https://docs.amd.com/v/u/en-US/ug1085-zynq-ultrascale-trm [2] https://docs.amd.com/r/en-US/ug1087-zynq-ultrascale-registers/transmit_q_ptr-GEM-RegisterFor what it's worth, I agree with Kevin. It should be rather easy to detect if the patch is needed, with more logging. Dump TBQP before link-down & dump it at link-up. The code expects TBQP to reset to the ring start automatically whereas this commit message says the TBQP after link-up is some offset into the ring.
These traces were captured on a zynqmp device. The patches in this series were not applied.
The traces contain information from both tx queues (q0 and q1).
tbqp contains the value returned by queue_readl(queue, TBQP).
base is lower_32_bits(queue->tx_ring_dma).
tbqp_ctrl contains macb_tx_desc(queue, tbqp_idx)->ctrl.
tail_ctrl contains macb_tx_desc(queue, queue->tx_tail)->ctrl.
At the beginning the link is up and communication over ethernet is working.
The cpu is not at 100% load, everything worked fine.
Trace 1 (everythink works as expected, no high cpu load):
The ethernet link goes down.
Trace from macb_mac_link_down():
kworker/0:4-1679 [000] .N... 141.796925: macb_tx_hw_state: macb_tx_hw_state q0 linkdown_pre_te tbqp=67cd0030 base=67cd0000 ncr=0010001c tsr=00000021 imr=3fffffff head=2 tail=2 tbqp_idx=343 tbqp_ctrl=80000000(used=1) tail_ctrl=80000000(used=1)
kworker/0:4-1679 [000] ..... 141.796958: macb_tx_hw_state: macb_tx_hw_state q1 linkdown_pre_te tbqp=67cda598 base=67cd8000 ncr=0010001c tsr=00000021 imr=00000ce6 head=3985 tail=3985 tbqp_idx=59 tbqp_ctrl=80000036(used=1) tail_ctrl=80000000(used=1)
ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE));
macb_writel(bp, NCR, ctrl);
kworker/0:4-1679 [000] ..... 141.796961: macb_tx_hw_state: macb_tx_hw_state q0 linkdown_post_te tbqp=67cd0030 base=67cd0000 ncr=00100010 tsr=00000021 imr=3fffffff head=2 tail=2 tbqp_idx=343 tbqp_ctrl=80000000(used=1) tail_ctrl=80000000(used=1)
kworker/0:4-1679 [000] ..... 141.796964: macb_tx_hw_state: macb_tx_hw_state q1 linkdown_post_te tbqp=67cd8000 base=67cd8000 ncr=00100010 tsr=00000021 imr=00000ce6 head=3985 tail=3985 tbqp_idx=170 tbqp_ctrl=0000800f(used=0) tail_ctrl=80000000(used=1)
Ethernet link goes up.
Trace from macb_mac_link_up():
kworker/0:3-190 [000] ..... 152.966203: macb_tx_hw_state: macb_tx_hw_state q0 linkup_post_shuffle tbqp=67cd0030 base=67cd0000 ncr=00100010 tsr=00000021 imr=3ffff305 head=0 tail=0 tbqp_idx=343 tbqp_ctrl=80000000(used=1) tail_ctrl=80018040(used=1)
kworker/0:3-190 [000] ..... 152.966206: macb_tx_hw_state: macb_tx_hw_state q1 linkup_post_shuffle tbqp=67cd8000 base=67cd8000 ncr=00100010 tsr=00000021 imr=00000004 head=0 tail=0 tbqp_idx=170 tbqp_ctrl=0000800f(used=0) tail_ctrl=0000800f(used=0)
macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
kworker/0:3-190 [000] ..... 152.966209: macb_tx_hw_state: macb_tx_hw_state q0 linkup_post_te tbqp=67cd0030 base=67cd0000 ncr=0010001c tsr=00000021 imr=3ffff305 head=0 tail=0 tbqp_idx=343 tbqp_ctrl=80000000(used=1) tail_ctrl=80018040(used=1)
kworker/0:3-190 [000] ..... 152.966211: macb_tx_hw_state: macb_tx_hw_state q1 linkup_post_te tbqp=67cd8000 base=67cd8000 ncr=0010001c tsr=00000021 imr=00000004 head=0 tail=0 tbqp_idx=170 tbqp_ctrl=0000800f(used=0) tail_ctrl=0000800f(used=0)
CPU load is normal, no issue in this trace.
tbqp on q0 is not reset to base. But in this case it did not result in the interrupt storm.
Trace 2 (results in interrupt storm):
The ethernet link goes down.
Trace from macb_mac_link_down():
kworker/0:3-95 [000] .N... 459.682957: macb_tx_hw_state: macb_tx_hw_state q0 linkdown_pre_te tbqp=67cd2cb8 base=67cd0000 ncr=0010001c tsr=00000021 imr=3fffffff head=4061 tail=4061 tbqp_idx=306 tbqp_ctrl=0000800f(used=0) tail_ctrl=80000000(used=1)
kworker/0:3-95 [000] ..... 459.682991: macb_tx_hw_state: macb_tx_hw_state q1 linkdown_pre_te tbqp=67cd85a0 base=67cd8000 ncr=0010001c tsr=00000021 imr=00000ce6 head=60 tail=60 tbqp_idx=230 tbqp_ctrl=80000036(used=1) tail_ctrl=80000000(used=1)
ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE));
macb_writel(bp, NCR, ctrl);
kworker/0:3-95 [000] ..... 459.682994: macb_tx_hw_state: macb_tx_hw_state q0 linkdown_post_te tbqp=67cd2cb8 base=67cd0000 ncr=00100010 tsr=00000021 imr=3fffffff head=4061 tail=4061 tbqp_idx=306 tbqp_ctrl=0000800f(used=0) tail_ctrl=80000000(used=1)
kworker/0:3-95 [000] ..... 459.682996: macb_tx_hw_state: macb_tx_hw_state q1 linkdown_post_te tbqp=67cd8000 base=67cd8000 ncr=00100010 tsr=00000021 imr=00000ce6 head=60 tail=60 tbqp_idx=170 tbqp_ctrl=80000036(used=1) tail_ctrl=80000000(used=1)
Ethernet link goes up.
Trace from macb_mac_link_up():
kworker/0:3-95 [000] ..... 470.292877: macb_tx_hw_state: macb_tx_hw_state q0 linkup_post_shuffle tbqp=67cd2cb8 base=67cd0000 ncr=00100010 tsr=00000021 imr=3ffff305 head=0 tail=0 tbqp_idx=306 tbqp_ctrl=0000800f(used=0) tail_ctrl=0000800f(used=0)
kworker/0:3-95 [000] ..... 470.292879: macb_tx_hw_state: macb_tx_hw_state q1 linkup_post_shuffle tbqp=67cd8000 base=67cd8000 ncr=00100010 tsr=00000021 imr=00000004 head=0 tail=0 tbqp_idx=170 tbqp_ctrl=80000036(used=1) tail_ctrl=80018040(used=1)
macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
kworker/0:3-95 [000] ..... 470.292882: macb_tx_hw_state: macb_tx_hw_state q0 linkup_post_te tbqp=67cd2cb8 base=67cd0000 ncr=0010001c tsr=00000021 imr=3ffff305 head=0 tail=0 tbqp_idx=306 tbqp_ctrl=0000800f(used=0) tail_ctrl=0000800f(used=0)
kworker/0:3-95 [000] ..... 470.292884: macb_tx_hw_state: macb_tx_hw_state q1 linkup_post_te tbqp=67cd8000 base=67cd8000 ncr=0010001c tsr=00000021 imr=00000004 head=0 tail=0 tbqp_idx=170 tbqp_ctrl=80000036(used=1) tail_ctrl=80018040(used=1)
After that sequence one CPU core is at 100% load continously executing the macb irq handler.
The issue seems to be q0. tbqp of q1 is properly reset to its base address.
tbqp of q0 is not changed as expected in link down when tx is disabled.
Are there any other details i could put into the trace to determine the root cause?
I suspect that some packet is still in transmission/ being processed and this might be the
reason why tbqp of q0 is not being reset. But i do not see that in this trace.
Lastly, the cover letter mentions that [PATCH 1/2] alone isn't enough. But it doesn't mention that [PATCH 2/2] alone doesn't solve the issue. This would be a useful test as well. On Tue Jul 7, 2026 at 3:36 PM CEST, Taedcke, Christian wrote:quoted
Thank you for the quick review! This is my first Linux kernel contribution, so I appreciate your feedback here.Welcome! Thanks, -- Théo Lebrun, Bootlin Embedded Linux and Kernel engineering https://bootlin.com/
Regards, Christian