diff mbox series

realtek: fix locking bug in rtl838x_hw_receive()

Message ID d3c2562c-d0bf-89f3-d0a4-6a51c30a590b@birger-koblitz.de
State Accepted
Delegated to: Daniel Golle
Headers show
Series realtek: fix locking bug in rtl838x_hw_receive() | expand

Commit Message

Birger Koblitz Feb. 18, 2022, 11:01 a.m. UTC
A Locking bug in the packet receive path was introduced with PR
#4973. The following patch prevents the driver from locking
after a few minutes with an endless flow of

[ 1434.185085] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last a28000f4, cur a28000f8
[ 1434.208971] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last a28000f4, cur a28000fc
[ 1434.794800] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last a28000f4, cur a28000fc
[ 1435.049187] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last a28000f4, cur a28000fc

Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Birger Koblitz <mail@birger-koblitz.de>
---
 .../realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c  | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

Comments

Sander Vanheule Feb. 18, 2022, 3:18 p.m. UTC | #1
Hi Birger,

On Fri, 2022-02-18 at 12:01 +0100, Birger Koblitz wrote:
> A Locking bug in the packet receive path was introduced with PR
> #4973. The following patch prevents the driver from locking
> after a few minutes with an endless flow of
> 
> [ 1434.185085] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last
> a28000f4, cur a28000f8
> [ 1434.208971] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last
> a28000f4, cur a28000fc
> [ 1434.794800] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last
> a28000f4, cur a28000fc
> [ 1435.049187] rtl838x-eth 1b00a300.ethernet eth0: Ring contention: r: 0, last
> a28000f4, cur a28000fc
> 
> Signed-off-by: Bjørn Mork <bjorn@mork.no>
> Signed-off-by: Birger Koblitz <mail@birger-koblitz.de>

If Bjørn signed off on this patch first, he should be the patch author too.
(i.e. start this patch with a From: line). This patch sounds like it should have
a Fixes: tag as well; if you can find out which patch introduced it.

Best,
Sander

> ---
>  .../realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c  | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/target/linux/realtek/files-
> 5.10/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-
> 5.10/drivers/net/ethernet/rtl838x_eth.c
> index ab4a03550bd8..cf6aabc6142f 100644
> --- a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
> +++ b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
> @@ -1254,8 +1254,9 @@ static int rtl838x_hw_receive(struct net_device *dev,
> int r, int budget)
>         bool dsa = netdev_uses_dsa(dev);
>         struct dsa_tag tag;
> 
> -       last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));
>         pr_debug("----------------------------------------------------------
> RX - %d\n", r);
> +       spin_lock_irqsave(&priv->lock, flags);
> +       last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));
> 
>         do {
>                 if ((ring->rx_r[r][ring->c_rx[r]] & 0x1)) {
> @@ -1329,7 +1330,6 @@ static int rtl838x_hw_receive(struct net_device *dev,
> int r, int budget)
>                 }
> 
>                 /* Reset header structure */
> -               spin_lock_irqsave(&priv->lock, flags);
>                 memset(h, 0, sizeof(struct p_hdr));
>                 h->buf = data;
>                 h->size = RING_BUFFER;
> @@ -1338,12 +1338,13 @@ static int rtl838x_hw_receive(struct net_device *dev,
> int r, int budget)
>                         | (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP :
> 0x1);
>                 ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen;
>                 last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r *
> 4));
> -               spin_unlock_irqrestore(&priv->lock, flags);
>         } while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget);
> 
>         // Update counters
>         priv->r->update_cntr(r, 0);
> 
> +       spin_unlock_irqrestore(&priv->lock, flags);
> +
>         return work_done;
>  }
>
Bjørn Mork Feb. 19, 2022, 10:37 a.m. UTC | #2
Sander Vanheule <sander@svanheule.net> writes:

> If Bjørn signed off on this patch first, he should be the patch author too.
> (i.e. start this patch with a From: line). This patch sounds like it should have
> a Fixes: tag as well; if you can find out which patch introduced it.

Sorry about the missing Fixes.  I meant to add it but was in a hurry and
forgot.

As for the author part - in principle I'd agree.  But this particular
change was actually dictated in detail  by Birger.  So it's not wrong to
make him author.

Besides, this is really a partial revert which should be merged into the
original patch before it goes anywhere.  Making it a completely
invisible no-op.



Bjørn
diff mbox series

Patch

diff --git a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
index ab4a03550bd8..cf6aabc6142f 100644
--- a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
+++ b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
@@ -1254,8 +1254,9 @@  static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
 	bool dsa = netdev_uses_dsa(dev);
 	struct dsa_tag tag;

-	last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));
 	pr_debug("---------------------------------------------------------- RX - %d\n", r);
+	spin_lock_irqsave(&priv->lock, flags);
+	last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));

 	do {
 		if ((ring->rx_r[r][ring->c_rx[r]] & 0x1)) {
@@ -1329,7 +1330,6 @@  static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
 		}

 		/* Reset header structure */
-		spin_lock_irqsave(&priv->lock, flags);
 		memset(h, 0, sizeof(struct p_hdr));
 		h->buf = data;
 		h->size = RING_BUFFER;
@@ -1338,12 +1338,13 @@  static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
 			| (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP : 0x1);
 		ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen;
 		last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));
-		spin_unlock_irqrestore(&priv->lock, flags);
 	} while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget);

 	// Update counters
 	priv->r->update_cntr(r, 0);

+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	return work_done;
 }