From: Birger Koblitz Date: Fri, 18 Feb 2022 11:01:53 +0000 (+0100) Subject: realtek: fix locking bug in rtl838x_hw_receive() X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=4d8020072ee291fe4e7b751e2c1490830932bcc4;p=openwrt%2Fstaging%2Frobimarko.git realtek: fix locking bug in rtl838x_hw_receive() 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 Signed-off-by: Birger Koblitz --- 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 ab4a03550b..cf6aabc614 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; }