Skip to content

Commit

Permalink
bgmac: fix DMA rx corruption
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Felix Fietkau authored and David S. Miller committed Apr 14, 2015
1 parent 74b6f29 commit 4668ae1
Showing 1 changed file with 18 additions and 9 deletions.
27 changes: 18 additions & 9 deletions drivers/net/ethernet/broadcom/bgmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
return 0;
}

static void bgmac_dma_rx_update_index(struct bgmac *bgmac,
struct bgmac_dma_ring *ring)
{
dma_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)
{
Expand All @@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac,
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;
}

static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
Expand Down Expand Up @@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
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;
Expand Down Expand Up @@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
break;
}

bgmac_dma_rx_update_index(bgmac, ring);

return handled;
}

Expand Down Expand Up @@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac *bgmac)
if (ring->unaligned)
bgmac_dma_rx_enable(bgmac, ring);

ring->start = 0;
ring->end = 0;
for (j = 0; j < ring->num_slots; j++) {
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
if (err)
Expand All @@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac *bgmac)
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);
}

return 0;
Expand Down

0 comments on commit 4668ae1

Please sign in to comment.