[PATCH net-next v3 13/15] net: macb: re-read ISR inside IRQ handler locked section
From: Théo Lebrun
Date: Wed Jul 01 2026 - 12:03:36 EST
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.
If we tried grabbing bp->lock while already acquired, we might have
slept and the status might have been updated. Our most likely
competitor in this race (condition) is a swap operation, used in
change_mtu and set_ringparam. It is the only MACB codepath that resets
interrupts and HW inside a bp->lock critical section. Other codepaths
that clear HW IRQ status do so outside the bp->lock critical section.
We can only detect spurious interrupts before grabbing bp->lock if
MACB_CAPS_ISR_CLEAR_ON_WRITE. If we don't, then we only read ISR once.
Signed-off-by: Théo Lebrun <theo.lebrun@xxxxxxxxxxx>
---
drivers/net/ethernet/cadence/macb_main.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 7245c345c78f..5a32d5cb759e 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2184,13 +2184,21 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
struct net_device *netdev = bp->netdev;
u32 status;
- status = queue_readl(queue, ISR);
-
- if (unlikely(!status))
- return IRQ_NONE;
+ /* detect spurious interrupts without grabbing bp->lock */
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) {
+ status = queue_readl(queue, ISR);
+ if (unlikely(!status))
+ return IRQ_NONE;
+ }
spin_lock(&bp->lock);
+ status = queue_readl(queue, ISR);
+ if (unlikely(!status)) {
+ spin_unlock(&bp->lock);
+ return IRQ_NONE;
+ }
+
while (status) {
/* close possible race with dev_close */
if (unlikely(!netif_running(netdev))) {
--
2.55.0