pcnet32: stop holding device spin lock during napi_complete_done
authorOscar Maes <oscmaes92@gmail.com>
Thu, 28 May 2026 14:03:20 +0000 (16:03 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 2 Jun 2026 18:26:30 +0000 (11:26 -0700)
napi_complete_done may call gro_flush_normal (though not currently, as GRO
is unsupported at the moment), which may result in packet TX. This will
eventually result in calling pcnet32_start_xmit - resulting in a deadlock
while trying to re-acquire the already locked spin lock.

It is safe to split the spinlock block into two, because the hardware
registers are still protected from concurrent access, and the two blocks
perform unrelated operations that don't need to happen atomically.

Fixes: 5b2ec6f2be51 ("pcnet32: use napi_complete_done()")
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Oscar Maes <oscmaes92@gmail.com>
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Link: https://patch.msgid.link/20260528140320.5556-1-oscmaes92@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/amd/pcnet32.c

index 911808a..4f3076d 100644 (file)
@@ -1407,8 +1407,10 @@ static int pcnet32_poll(struct napi_struct *napi, int budget)
                pcnet32_restart(dev, CSR0_START);
                netif_wake_queue(dev);
        }
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        if (work_done < budget && napi_complete_done(napi, work_done)) {
+               spin_lock_irqsave(&lp->lock, flags);
                /* clear interrupt masks */
                val = lp->a->read_csr(ioaddr, CSR3);
                val &= 0x00ff;
@@ -1416,9 +1418,9 @@ static int pcnet32_poll(struct napi_struct *napi, int budget)
 
                /* Set interrupt enable. */
                lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN);
+               spin_unlock_irqrestore(&lp->lock, flags);
        }
 
-       spin_unlock_irqrestore(&lp->lock, flags);
        return work_done;
 }