Skip to content

Commit

Permalink
realtek: fix locking bug in rtl838x_hw_receive()
Browse files Browse the repository at this point in the history
A Locking bug in the packet receive path was introduced with PR
openwrt#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>
  • Loading branch information
logicog authored and dangowrt committed Feb 18, 2022
1 parent e9e61d7 commit 4d80200
Showing 1 changed file with 4 additions and 3 deletions.
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down

0 comments on commit 4d80200

Please sign in to comment.