bcm4908_enet_stop() disables the TX DMA but leaves the ring as it is: the skbs of frames not completed yet stay mapped and are never freed, and their descriptors keep DMA_CTL_STATUS_OWN. The next open starts the indexes from 0 again over those descriptors, so the DMA can send from a buffer that has been freed, and start_xmit() finds OWN set on a slot it is about to use. Unmap and free the skbs left in the TX ring on stop, clear slot->skb once poll_tx() has freed it, and clear the TX descriptors when the ring is initialised. Fixes: 4feffeadbcb2 ("net: broadcom: bcm4908enet: add BCM4908 controller driver") Signed-off-by: Kordian Chmielewski (mlody1212) --- drivers/net/ethernet/broadcom/bcm4908_enet.c | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c index 727ad1e96..8008b44a4 100644 --- a/drivers/net/ethernet/broadcom/bcm4908_enet.c +++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c @@ -312,6 +312,10 @@ static void bcm4908_enet_dma_ring_init(struct bcm4908_enet *enet, enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, (uint32_t)ring->dma_addr); + /* A descriptor the stopped DMA never completed still carries OWN */ + if (ring->is_tx) + memset(ring->cpu_addr, 0, ring->length * sizeof(*ring->buf_desc)); + ring->read_idx = 0; ring->write_idx = 0; } @@ -495,6 +499,23 @@ static int bcm4908_enet_open(struct net_device *netdev) return 0; } +static void bcm4908_enet_tx_ring_clean(struct bcm4908_enet *enet) +{ + struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring; + struct device *dev = enet->dev; + int i; + + for (i = 0; i < tx_ring->length; i++) { + struct bcm4908_enet_dma_ring_slot *slot = &tx_ring->slots[i]; + + if (!slot->skb) + continue; + dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE); + dev_kfree_skb_any(slot->skb); + slot->skb = NULL; + } +} + static int bcm4908_enet_stop(struct net_device *netdev) { struct bcm4908_enet *enet = netdev_priv(netdev); @@ -510,6 +531,7 @@ static int bcm4908_enet_stop(struct net_device *netdev) bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring); bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring); + bcm4908_enet_tx_ring_clean(enet); bcm4908_enet_dma_uninit(enet); free_irq(enet->irq_tx, enet); @@ -686,6 +708,7 @@ static int bcm4908_enet_poll_tx(struct napi_struct *napi, int weight) dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE); dev_kfree_skb(slot->skb); + slot->skb = NULL; handled++; bytes += slot->len; -- 2.56.0