Skip to content

Commit b690f8d

Browse files
AndybnACTdavem330
authored andcommitted
net: axienet: Use iowrite64 to write all 64b descriptor pointers
According to commit f735c40 ("net: axienet: Autodetect 64-bit DMA capability") and AXI-DMA spec (pg021), on 64-bit capable dma, only writing MSB part of tail descriptor pointer causes DMA engine to start fetching descriptors. However, we found that it is true only if dma is in idle state. In other words, dma would use a tailp even if it only has LSB updated, when the dma is running. The non-atomicity of this behavior could be problematic if enough delay were introduced in between the 2 writes. For example, if an interrupt comes right after the LSB write and the cpu spends long enough time in the handler for the dma to get back into idle state by completing descriptors, then the seconcd write to MSB would treat dma to start fetching descriptors again. Since the descriptor next to the one pointed by current tail pointer is not filled by the kernel yet, fetching a null descriptor here causes a dma internal error and halt the dma engine down. We suggest that the dma engine should start process a 64-bit MMIO write to the descriptor pointer only if ONE 32-bit part of it is written on all states. Or we should restrict the use of 64-bit addressable dma on 32-bit platforms, since those devices have no instruction to guarantee the write to LSB and MSB part of tail pointer occurs atomically to the dma. initial condition: curp = x-3; tailp = x-2; LSB = x; MSB = 0; cpu: |dma: iowrite32(LSB, tailp) | completes #(x-3) desc, curp = x-3 ... | tailp updated => irq | completes #(x-2) desc, curp = x-2 ... | completes #(x-1) desc, curp = x-1 ... | ... ... | completes #x desc, curp = tailp = x <= irqreturn | reaches tailp == curp = x, idle iowrite32(MSB, tailp + 4) | ... | tailp updated, starts fetching... | fetches #(x + 1) desc, sees cntrl = 0 | post Tx error, halt Signed-off-by: Andy Chiu <andy.chiu@sifive.com> Reported-by: Max Hsu <max.hsu@sifive.com> Reviewed-by: Greentime Hu <greentime.hu@sifive.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 00be43a commit b690f8d

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

drivers/net/ethernet/xilinx/xilinx_axienet.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -564,13 +564,28 @@ static inline void axienet_dma_out32(struct axienet_local *lp,
564564
}
565565

566566
#ifdef CONFIG_64BIT
567+
/**
568+
* axienet_dma_out64 - Memory mapped Axi DMA register write.
569+
* @lp: Pointer to axienet local structure
570+
* @reg: Address offset from the base address of the Axi DMA core
571+
* @value: Value to be written into the Axi DMA register
572+
*
573+
* This function writes the desired value into the corresponding Axi DMA
574+
* register.
575+
*/
576+
static inline void axienet_dma_out64(struct axienet_local *lp,
577+
off_t reg, u64 value)
578+
{
579+
iowrite64(value, lp->dma_regs + reg);
580+
}
581+
567582
static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
568583
dma_addr_t addr)
569584
{
570-
axienet_dma_out32(lp, reg, lower_32_bits(addr));
571-
572585
if (lp->features & XAE_FEATURE_DMA_64BIT)
573-
axienet_dma_out32(lp, reg + 4, upper_32_bits(addr));
586+
axienet_dma_out64(lp, reg, addr);
587+
else
588+
axienet_dma_out32(lp, reg, lower_32_bits(addr));
574589
}
575590

576591
#else /* CONFIG_64BIT */

0 commit comments

Comments
 (0)