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

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
Loading
Loading
Loading
Loading
+22 −5
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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 */