bcm4908_enet_dma_alloc_rx_buf() hands a descriptor to the DMA by writing its control word, with DMA_CTL_STATUS_OWN, first and the new buffer address second. If the DMA read the descriptor between the two stores, it would write the next frame into the old buffer, which poll_rx() is turning into an skb. start_xmit() writes the address first, but nothing orders the two stores, and the descriptors live in coherent memory, where arm64 may make them visible in either order. Write the address first on both paths and order it before the control word with dma_wmb(). In poll_rx(), read what the DMA wrote only after seeing OWN clear (dma_rmb()), as Documentation/memory-barriers.txt describes for descriptors shared with a device. Found by reading the code; I have no test that shows the DMA reading a descriptor while it is being refilled. Fixes: 4feffeadbcb2 ("net: broadcom: bcm4908enet: add BCM4908 controller driver") Reviewed-by: Florian Fainelli Signed-off-by: Kordian Chmielewski --- drivers/net/ethernet/broadcom/bcm4908_enet.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c index 4065769da..4139dad3a 100644 --- a/drivers/net/ethernet/broadcom/bcm4908_enet.c +++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c @@ -291,8 +291,10 @@ static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int tmp |= DMA_CTL_STATUS_OWN; if (idx == enet->rx_ring.length - 1) tmp |= DMA_CTL_STATUS_WRAP; - buf_desc->ctl = cpu_to_le32(tmp); buf_desc->addr = cpu_to_le32(slot->dma_addr); + /* Hand the descriptor to the DMA only once it holds the new buffer */ + dma_wmb(); + buf_desc->ctl = cpu_to_le32(tmp); return 0; } @@ -613,6 +615,8 @@ static netdev_tx_t bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_devic netdev_sent_queue(enet->netdev, skb->len); buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr); + /* The DMA must not see OWN before the buffer address */ + dma_wmb(); buf_desc->ctl = cpu_to_le32(tmp); bcm4908_enet_dma_tx_ring_enable(enet, &enet->tx_ring); @@ -647,6 +651,8 @@ static int bcm4908_enet_poll_rx(struct napi_struct *napi, int weight) ctl = le32_to_cpu(buf_desc->ctl); if (ctl & DMA_CTL_STATUS_OWN) break; + /* Read the rest only after the DMA gave the descriptor back */ + dma_rmb(); slot = enet->rx_ring.slots[enet->rx_ring.read_idx]; -- 2.56.1