Skip to content

Commit a7ffce9

Browse files
committed
Merge branch 'axienet-fixes'
Andy Chiu says: ==================== net: axienet: fix DMA Tx error We ran into multiple DMA TX errors while writing files over a network block device running on top of a DMA-connected AXI Ethernet device on 64-bit RISC-V machines. The errors indicated that the DMA had fetched a null descriptor and we found that the reason for this is that AXI DMA had unexpectedly processed a partially updated tail descriptor pointer. To fix it, we suggest that the driver should use one 64-bit write instead of two 32-bit writes to perform such update if possible. For those archectures where double-word load/stores are unavailable, e.g. 32-bit archectures, force a driver probe failure if the driver finds 64-bit capability on DMA. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents a5b00f5 + b690f8d commit a7ffce9

2 files changed

Lines changed: 55 additions & 24 deletions

File tree

drivers/net/ethernet/xilinx/xilinx_axienet.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,57 @@ static inline void axienet_iow(struct axienet_local *lp, off_t offset,
547547
iowrite32(value, lp->regs + offset);
548548
}
549549

550+
/**
551+
* axienet_dma_out32 - Memory mapped Axi DMA register write.
552+
* @lp: Pointer to axienet local structure
553+
* @reg: Address offset from the base address of the Axi DMA core
554+
* @value: Value to be written into the Axi DMA register
555+
*
556+
* This function writes the desired value into the corresponding Axi DMA
557+
* register.
558+
*/
559+
560+
static inline void axienet_dma_out32(struct axienet_local *lp,
561+
off_t reg, u32 value)
562+
{
563+
iowrite32(value, lp->dma_regs + reg);
564+
}
565+
566+
#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+
582+
static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
583+
dma_addr_t addr)
584+
{
585+
if (lp->features & XAE_FEATURE_DMA_64BIT)
586+
axienet_dma_out64(lp, reg, addr);
587+
else
588+
axienet_dma_out32(lp, reg, lower_32_bits(addr));
589+
}
590+
591+
#else /* CONFIG_64BIT */
592+
593+
static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
594+
dma_addr_t addr)
595+
{
596+
axienet_dma_out32(lp, reg, lower_32_bits(addr));
597+
}
598+
599+
#endif /* CONFIG_64BIT */
600+
550601
/* Function prototypes visible in xilinx_axienet_mdio.c for other files */
551602
int axienet_mdio_enable(struct axienet_local *lp);
552603
void axienet_mdio_disable(struct axienet_local *lp);

drivers/net/ethernet/xilinx/xilinx_axienet_main.c

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,30 +133,6 @@ static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
133133
return ioread32(lp->dma_regs + reg);
134134
}
135135

136-
/**
137-
* axienet_dma_out32 - Memory mapped Axi DMA register write.
138-
* @lp: Pointer to axienet local structure
139-
* @reg: Address offset from the base address of the Axi DMA core
140-
* @value: Value to be written into the Axi DMA register
141-
*
142-
* This function writes the desired value into the corresponding Axi DMA
143-
* register.
144-
*/
145-
static inline void axienet_dma_out32(struct axienet_local *lp,
146-
off_t reg, u32 value)
147-
{
148-
iowrite32(value, lp->dma_regs + reg);
149-
}
150-
151-
static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
152-
dma_addr_t addr)
153-
{
154-
axienet_dma_out32(lp, reg, lower_32_bits(addr));
155-
156-
if (lp->features & XAE_FEATURE_DMA_64BIT)
157-
axienet_dma_out32(lp, reg + 4, upper_32_bits(addr));
158-
}
159-
160136
static void desc_set_phys_addr(struct axienet_local *lp, dma_addr_t addr,
161137
struct axidma_bd *desc)
162138
{
@@ -2061,6 +2037,10 @@ static int axienet_probe(struct platform_device *pdev)
20612037
iowrite32(0x0, desc);
20622038
}
20632039
}
2040+
if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) {
2041+
dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n");
2042+
goto cleanup_clk;
2043+
}
20642044

20652045
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width));
20662046
if (ret) {

0 commit comments

Comments
 (0)