From: Felix Fietkau Date: Sun, 12 Apr 2015 11:59:47 +0200 Subject: [PATCH] bgmac: fix DMA rx corruption The driver needs to inform the hardware about the first invalid (not yet filled) rx slot, by writing its DMA descriptor pointer offset to the BGMAC_DMA_RX_INDEX register. This register was set to a value exceeding the rx ring size, effectively allowing the hardware constant access to the full ring, regardless of which slots are initialized. Fix this by updating the register in bgmac_dma_rx_setup_desc. Signed-off-by: Felix Fietkau --- --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -362,6 +362,16 @@ static int bgmac_dma_rx_skb_for_slot(str return 0; } +static void bgmac_dma_rx_update_index(struct bgmac *bgmac, + struct bgmac_dma_ring *ring) +{ + wmb(); + + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, + ring->index_base + + ring->end * sizeof(struct bgmac_dma_desc)); +} + static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac, struct bgmac_dma_ring *ring, int desc_idx) { @@ -380,6 +390,8 @@ static void bgmac_dma_rx_setup_desc(stru dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr)); dma_desc->ctl0 = cpu_to_le32(ctl0); dma_desc->ctl1 = cpu_to_le32(ctl1); + + ring->end = (desc_idx + 1) % BGMAC_RX_RING_SLOTS; } static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, @@ -394,9 +406,7 @@ static int bgmac_dma_rx_read(struct bgma end_slot &= BGMAC_DMA_RX_STATDPTR; end_slot /= sizeof(struct bgmac_dma_desc); - ring->end = end_slot; - - while (ring->start != ring->end) { + while (ring->start != end_slot) { struct device *dma_dev = bgmac->core->dma_dev; struct bgmac_slot_info *slot = &ring->slots[ring->start]; struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; @@ -468,6 +478,8 @@ static int bgmac_dma_rx_read(struct bgma break; } + bgmac_dma_rx_update_index(bgmac, ring); + return handled; } @@ -690,15 +702,12 @@ static void bgmac_dma_init(struct bgmac if (ring->unaligned) bgmac_dma_rx_enable(bgmac, ring); + ring->start = 0; + ring->end = 0; for (j = 0; j < ring->num_slots; j++) bgmac_dma_rx_setup_desc(bgmac, ring, j); - bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, - ring->index_base + - ring->num_slots * sizeof(struct bgmac_dma_desc)); - - ring->start = 0; - ring->end = 0; + bgmac_dma_rx_update_index(bgmac, ring); } }