lantiq: fix sleep with spinlock held in xrx200 network driver
authorAndrea Merello <andrea.merello@gmail.com>
Sat, 8 Jul 2017 08:11:11 +0000 (10:11 +0200)
committerMathias Kresin <dev@kresin.me>
Thu, 20 Jul 2017 17:10:29 +0000 (19:10 +0200)
In the xrx200_close() function we call napi_disable(), that could
sleep, with priv->hw->chan[i].lock held. This could lead to deadlock
and causes the kernel to complain.

Look at the code I couldn't convince myself about why we
need to protect that specific code part with the lock. IMHO there
seems no reason to protect the refcount variables, because AFAIK
ndo_close() and ndo_open() callbacks are already called with a
semaphore held. Neither I could figure out why napi_disable() have to
be called with that lock held. The only remaining code part for
which I could guess the lock is useful for is ltq_dma_close()
function call.

This patch reduces the lock to the said function call, avoiding the
sleep-with-spinlock-held situation

Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
[fold into 0025-NET-MIPS-lantiq-adds-xrx200-net.patch, backport to
kernel 4.4]
Signed-off-by: Mathias Kresin <dev@kresin.me>
target/linux/lantiq/patches-4.4/0025-NET-MIPS-lantiq-adds-xrx200-net.patch
target/linux/lantiq/patches-4.9/0025-NET-MIPS-lantiq-adds-xrx200-net.patch

index 1550f26e36f96244122204f488590dd1e9e3963d..ccb0733f75ed5483ad921554e1ced2b13a0f9984 100644 (file)
@@ -209,7 +209,7 @@ Subject: [PATCH 25/36] NET: MIPS: lantiq: adds xrx200-net
 +};
 --- /dev/null
 +++ b/drivers/net/ethernet/lantiq_xrx200.c
-@@ -0,0 +1,1852 @@
+@@ -0,0 +1,1853 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify it
 + *   under the terms of the GNU General Public License version 2 as published
@@ -1110,14 +1110,15 @@ Subject: [PATCH 25/36] NET: MIPS: lantiq: adds xrx200-net
 +      for (i = 0; i < XRX200_MAX_DMA; i++) {
 +              if (!priv->hw->chan[i].dma.irq)
 +                      continue;
-+              spin_lock_bh(&priv->hw->chan[i].lock);
++
 +              priv->hw->chan[i].refcount--;
 +              if (!priv->hw->chan[i].refcount) {
 +                      if (XRX200_DMA_IS_RX(i))
 +                              napi_disable(&priv->hw->chan[i].napi);
++                      spin_lock_bh(&priv->hw->chan[i].lock);
 +                      ltq_dma_close(&priv->hw->chan[XRX200_DMA_RX].dma);
++                      spin_unlock_bh(&priv->hw->chan[i].lock);
 +              }
-+              spin_unlock_bh(&priv->hw->chan[i].lock);
 +      }
 +
 +      return 0;
index 80bcea0f4b90b69ef34d72c296a668919bc7a0d5..871176449cdcc3b07dab72df0894931971be697d 100644 (file)
@@ -209,7 +209,7 @@ Subject: [PATCH 25/36] NET: MIPS: lantiq: adds xrx200-net
 +};
 --- /dev/null
 +++ b/drivers/net/ethernet/lantiq_xrx200.c
-@@ -0,0 +1,1851 @@
+@@ -0,0 +1,1852 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify it
 + *   under the terms of the GNU General Public License version 2 as published
@@ -1110,14 +1110,15 @@ Subject: [PATCH 25/36] NET: MIPS: lantiq: adds xrx200-net
 +      for (i = 0; i < XRX200_MAX_DMA; i++) {
 +              if (!priv->hw->chan[i].dma.irq)
 +                      continue;
-+              spin_lock_bh(&priv->hw->chan[i].lock);
++
 +              priv->hw->chan[i].refcount--;
 +              if (!priv->hw->chan[i].refcount) {
 +                      if (XRX200_DMA_IS_RX(i))
 +                              napi_disable(&priv->hw->chan[i].napi);
++                      spin_lock_bh(&priv->hw->chan[i].lock);
 +                      ltq_dma_close(&priv->hw->chan[XRX200_DMA_RX].dma);
++                      spin_unlock_bh(&priv->hw->chan[i].lock);
 +              }
-+              spin_unlock_bh(&priv->hw->chan[i].lock);
 +      }
 +
 +      return 0;