Commit a9d6d897 authored by David S. Miller's avatar David S. Miller

Merge branch 'macb-DMA-race-fixes'

Anssi Hannula says:

====================
net: macb: DMA race condition fixes

Here are a couple of race condition fixes for the macb driver. The first
two are for issues observed at runtime on real HW.

v2:
- added received Tested-bys and Acked-bys to the first two patches
- in patch 3/3, moved the timestamp protection barrier closer to the
  timestamp reads
- in patch 3/3, removed unnecessary move of the addr assignment in
  gem_rx() to keep the patch minimal for maximum clarity
- in patch 3/3, clarified commit message and comments

The 3/3 is the same one I improperly sent last week as a standalone
patch.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e2c4cf7f 6e0af298
......@@ -681,6 +681,11 @@ static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_
if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
desc_64 = macb_64b_desc(bp, desc);
desc_64->addrh = upper_32_bits(addr);
/* The low bits of RX address contain the RX_USED bit, clearing
* of which allows packet RX. Make sure the high bits are also
* visible to HW at that point.
*/
dma_wmb();
}
#endif
desc->addr = lower_32_bits(addr);
......@@ -929,14 +934,19 @@ static void gem_rx_refill(struct macb_queue *queue)
if (entry == bp->rx_ring_size - 1)
paddr |= MACB_BIT(RX_WRAP);
macb_set_addr(bp, desc, paddr);
desc->ctrl = 0;
/* Setting addr clears RX_USED and allows reception,
* make sure ctrl is cleared first to avoid a race.
*/
dma_wmb();
macb_set_addr(bp, desc, paddr);
/* properly align Ethernet header */
skb_reserve(skb, NET_IP_ALIGN);
} else {
desc->addr &= ~MACB_BIT(RX_USED);
desc->ctrl = 0;
dma_wmb();
desc->addr &= ~MACB_BIT(RX_USED);
}
}
......@@ -990,11 +1000,15 @@ static int gem_rx(struct macb_queue *queue, int budget)
rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
addr = macb_get_addr(bp, desc);
ctrl = desc->ctrl;
if (!rxused)
break;
/* Ensure ctrl is at least as up-to-date as rxused */
dma_rmb();
ctrl = desc->ctrl;
queue->rx_tail++;
count++;
......@@ -1169,11 +1183,14 @@ static int macb_rx(struct macb_queue *queue, int budget)
/* Make hw descriptor updates visible to CPU */
rmb();
ctrl = desc->ctrl;
if (!(desc->addr & MACB_BIT(RX_USED)))
break;
/* Ensure ctrl is at least as up-to-date as addr */
dma_rmb();
ctrl = desc->ctrl;
if (ctrl & MACB_BIT(RX_SOF)) {
if (first_frag != -1)
discard_partial_frame(queue, first_frag, tail);
......
......@@ -319,6 +319,8 @@ int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb,
desc_ptp = macb_ptp_desc(queue->bp, desc);
tx_timestamp = &queue->tx_timestamps[head];
tx_timestamp->skb = skb;
/* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */
dma_rmb();
tx_timestamp->desc_ptp.ts_1 = desc_ptp->ts_1;
tx_timestamp->desc_ptp.ts_2 = desc_ptp->ts_2;
/* move head */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment