Thread (26 messages) flat view 26 messages, 3 authors, 9d ago

Re: [PATCH net-next v9 15/17] net: macb: read ISR inside bp->lock critical section

From: Théo Lebrun <theo.lebrun@bootlin.com>
Date: 2026-09-11 17:34:34
Also in: lkml

Replying to non-net sashiko
https://sashiko.dev/#/patchset/20260812-macb-context-v9-0-7ddbf5f715e0%40bootlin.com
commit 48c8a049fccfd5d7c55b15a7fd08dc4eca66d836
Author: Théo Lebrun [off-list ref]
Date:   Wed Aug 12 08:03:29 2026 +0000

    net: macb: read ISR inside bp->lock critical section
    
    The IRQ handler reads ISR register into the `status` stack variable.
    If empty, it early returns. Else, it grabs bp->lock and iterates on
    the status bits.
    
    We risk a race on spinlock acquire; status might have changed.
    Move the readl(ISR) inside the bp->lock critical section.
quoted
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index d23a0d08c2769..6d79663e42bfe 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2190,12 +2190,13 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
 	bool hresp_err = false;
 	u32 status;
 
-	status = queue_readl(queue, ISR);
+	spin_lock(&bp->lock);
[Severity: High]
Does taking this lock unconditionally cause severe latency spikes for other
devices on a shared interrupt line?

If a shared interrupt fires while the driver's error handling task is running,
this CPU might spin with local interrupts disabled for up to 14ms:

macb_tx_error_task()
    spin_lock(&bp->lock);
    macb_halt_tx()
        read_poll_timeout_atomic(..., MACB_HALT_TIMEOUT, ...)

(MACB_HALT_TIMEOUT is 14000us)
Yes this is correct. And something we will live with.
 - Our IRQ line is shared only with other queues of the same MAC.
 - That timeout is scaled to 10 Mbits/s, on 1G this timeout should be
   100 times smaller. We just don't bother scaling it with link speed.

[...]
quoted
-	if (unlikely(!status))
+	status = queue_readl(queue, ISR);
[Severity: High]
This is a pre-existing issue, but can this unconditional hardware register
read trigger a synchronous external abort (bus fault) if the MAC is in
runtime suspend?

If another device on the same shared IRQ line triggers an interrupt while
the MAC's clocks are gated via macb_clks_disable() in macb_runtime_suspend(),
accessing memory-mapped registers of a clock-gated peripheral typically
causes a bus fault.
Again, we have IRQF_SHARED only to share with other queues of the same
MAC. So that theory is moot. Long term I'd like to drop IRQF_SHARED.
quoted
+	if (unlikely(!status)) {
+		spin_unlock(&bp->lock);
 		return IRQ_NONE;
-
-	spin_lock(&bp->lock);
+	}
 
 	while (status) {
[Severity: High]
This is a pre-existing issue, but will this loop infinitely if an unhandled
interrupt bit (like PFR) is set on hardware with Write-1-to-Clear ISR
behavior?
Yes. Long term I'd like to introduce a max iteration count.
Completely unrelated to context swapping.
[Severity: High]
This isn't a bug introduced by this patch, but does the driver have a
use-after-free risk during interface closure or driver removal?

In macb_close(), the context structure is freed without synchronizing with
or cancelling the asynchronous error tasks:
Yes. This one I'll fix. See previous email.

Re: [PATCH net-next v9 08/17] net: macb: introduce macb_context struct for buffer management
https://lore.kernel.org/netdev/DLCLQPVD8B9N.NFKWDS6SH0QN@bootlin.com/ (local)

[...]

---

Replying to net sashiko
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260812-macb-context-v9-0-7ddbf5f715e0%40bootlin.com
commit 4cc0cf203c223199f230330ef1014c2cac4c4841
Author: Théo Lebrun [off-list ref]

net: macb: read ISR inside bp->lock critical section

This moves the queue_readl(queue, ISR) in macb_interrupt() from before the
bp->lock acquisition to inside the critical section, and unlocks on the
early return path when status is zero.  The stated goal is to avoid acting
on a stale ISR sample.
quoted
We risk a race on spinlock acquire; status might have changed.
Move the readl(ISR) inside the bp->lock critical section.

In practice, we protect ourselves from interpreting the same ISR status
twice.
[Severity: Low]
[Finding: gpt-5-6-sol-1-3]
[Sources: gpt-5-6-sol, opus-5]
Could the changelog name the two contexts that can observe the same ISR
sample, and the hardware precondition?
If any other context clears an IRQ then we race against that. Grep for
macb_queue_isr_clear in the code; for example the suspend !WOL case.
Maybe the commit message is badly written; it isn't a notion of
interpreting the same bit twice.

[...]
quoted
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index d23a0d08c276..6d79663e42bf 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2190,12 +2190,13 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
 	bool hresp_err = false;
 	u32 status;
 
-	status = queue_readl(queue, ISR);
+	spin_lock(&bp->lock);
 
-	if (unlikely(!status))
+	status = queue_readl(queue, ISR);
+	if (unlikely(!status)) {
+		spin_unlock(&bp->lock);
 		return IRQ_NONE;
-
-	spin_lock(&bp->lock);
+	}
[Severity: Medium]
[Finding: main-3-6]
[Sources: opus-5]
Does this remove the lock-free "not my interrupt" fast path?

The handler is registered shared in macb_init():
Yes! Once again, we share only with other queues of the same MAC.
We don't support running alongside other devices.

[...]

Thanks,
-- 
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help