]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: cadence: macb: Fix a possible deadlock in macb_halt_tx.
authorMathieu Othacehe <othacehe@gnu.org>
Fri, 9 May 2025 12:19:35 +0000 (14:19 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 13 May 2025 01:39:38 +0000 (18:39 -0700)
There is a situation where after THALT is set high, TGO stays high as
well. Because jiffies are never updated, as we are in a context with
interrupts disabled, we never exit that loop and have a deadlock.

That deadlock was noticed on a sama5d4 device that stayed locked for days.

Use retries instead of jiffies so that the timeout really works and we do
not have a deadlock anymore.

Fixes: e86cd53afc590 ("net/macb: better manage tx errors")
Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250509121935.16282-1-othacehe@gnu.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/cadence/macb_main.c

index 1fe8ec37491b1912e321e3c8d8823159176c41a3..e1e8bd2ec155b8938095c9d7a63a891cbf4438ed 100644 (file)
@@ -997,22 +997,15 @@ static void macb_update_stats(struct macb *bp)
 
 static int macb_halt_tx(struct macb *bp)
 {
-       unsigned long   halt_time, timeout;
-       u32             status;
+       u32 status;
 
        macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));
 
-       timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT);
-       do {
-               halt_time = jiffies;
-               status = macb_readl(bp, TSR);
-               if (!(status & MACB_BIT(TGO)))
-                       return 0;
-
-               udelay(250);
-       } while (time_before(halt_time, timeout));
-
-       return -ETIMEDOUT;
+       /* Poll TSR until TGO is cleared or timeout. */
+       return read_poll_timeout_atomic(macb_readl, status,
+                                       !(status & MACB_BIT(TGO)),
+                                       250, MACB_HALT_TIMEOUT, false,
+                                       bp, TSR);
 }
 
 static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budget)