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: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
a9d6d897f3
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче