Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

To fix this issue, always mark the last filled rx slot as invalid.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Felix Fietkau and committed by
David S. Miller
4668ae1f 74b6f291

+18 -9
+18 -9
drivers/net/ethernet/broadcom/bgmac.c
··· 366 366 return 0; 367 367 } 368 368 369 + static void bgmac_dma_rx_update_index(struct bgmac *bgmac, 370 + struct bgmac_dma_ring *ring) 371 + { 372 + dma_wmb(); 373 + 374 + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, 375 + ring->index_base + 376 + ring->end * sizeof(struct bgmac_dma_desc)); 377 + } 378 + 369 379 static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac, 370 380 struct bgmac_dma_ring *ring, int desc_idx) 371 381 { ··· 394 384 dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr)); 395 385 dma_desc->ctl0 = cpu_to_le32(ctl0); 396 386 dma_desc->ctl1 = cpu_to_le32(ctl1); 387 + 388 + ring->end = desc_idx; 397 389 } 398 390 399 391 static void bgmac_dma_rx_poison_buf(struct device *dma_dev, ··· 423 411 end_slot &= BGMAC_DMA_RX_STATDPTR; 424 412 end_slot /= sizeof(struct bgmac_dma_desc); 425 413 426 - ring->end = end_slot; 427 - 428 - while (ring->start != ring->end) { 414 + while (ring->start != end_slot) { 429 415 struct device *dma_dev = bgmac->core->dma_dev; 430 416 struct bgmac_slot_info *slot = &ring->slots[ring->start]; 431 417 struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; ··· 485 475 if (handled >= weight) /* Should never be greater */ 486 476 break; 487 477 } 478 + 479 + bgmac_dma_rx_update_index(bgmac, ring); 488 480 489 481 return handled; 490 482 } ··· 707 695 if (ring->unaligned) 708 696 bgmac_dma_rx_enable(bgmac, ring); 709 697 698 + ring->start = 0; 699 + ring->end = 0; 710 700 for (j = 0; j < ring->num_slots; j++) { 711 701 err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); 712 702 if (err) ··· 717 703 bgmac_dma_rx_setup_desc(bgmac, ring, j); 718 704 } 719 705 720 - bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, 721 - ring->index_base + 722 - ring->num_slots * sizeof(struct bgmac_dma_desc)); 723 - 724 - ring->start = 0; 725 - ring->end = 0; 706 + bgmac_dma_rx_update_index(bgmac, ring); 726 707 } 727 708 728 709 return 0;