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

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: default avatarDavid S. Miller <davem@davemloft.net>
parents a5b00f5b b690f8df
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
@@ -547,6 +547,57 @@ static inline void axienet_iow(struct axienet_local *lp, off_t offset,
	iowrite32(value, lp->regs + offset);
}

/**
 * axienet_dma_out32 - Memory mapped Axi DMA register write.
 * @lp:		Pointer to axienet local structure
 * @reg:	Address offset from the base address of the Axi DMA core
 * @value:	Value to be written into the Axi DMA register
 *
 * This function writes the desired value into the corresponding Axi DMA
 * register.
 */

static inline void axienet_dma_out32(struct axienet_local *lp,
				     off_t reg, u32 value)
{
	iowrite32(value, lp->dma_regs + reg);
}

#ifdef CONFIG_64BIT
/**
 * axienet_dma_out64 - Memory mapped Axi DMA register write.
 * @lp:		Pointer to axienet local structure
 * @reg:	Address offset from the base address of the Axi DMA core
 * @value:	Value to be written into the Axi DMA register
 *
 * This function writes the desired value into the corresponding Axi DMA
 * register.
 */
static inline void axienet_dma_out64(struct axienet_local *lp,
				     off_t reg, u64 value)
{
	iowrite64(value, lp->dma_regs + reg);
}

static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
				 dma_addr_t addr)
{
	if (lp->features & XAE_FEATURE_DMA_64BIT)
		axienet_dma_out64(lp, reg, addr);
	else
		axienet_dma_out32(lp, reg, lower_32_bits(addr));
}

#else /* CONFIG_64BIT */

static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
				 dma_addr_t addr)
{
	axienet_dma_out32(lp, reg, lower_32_bits(addr));
}

#endif /* CONFIG_64BIT */

/* Function prototypes visible in xilinx_axienet_mdio.c for other files */
int axienet_mdio_enable(struct axienet_local *lp);
void axienet_mdio_disable(struct axienet_local *lp);
+4 −24
Original line number Diff line number Diff line
@@ -133,30 +133,6 @@ static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
	return ioread32(lp->dma_regs + reg);
}

/**
 * axienet_dma_out32 - Memory mapped Axi DMA register write.
 * @lp:		Pointer to axienet local structure
 * @reg:	Address offset from the base address of the Axi DMA core
 * @value:	Value to be written into the Axi DMA register
 *
 * This function writes the desired value into the corresponding Axi DMA
 * register.
 */
static inline void axienet_dma_out32(struct axienet_local *lp,
				     off_t reg, u32 value)
{
	iowrite32(value, lp->dma_regs + reg);
}

static void axienet_dma_out_addr(struct axienet_local *lp, off_t reg,
				 dma_addr_t addr)
{
	axienet_dma_out32(lp, reg, lower_32_bits(addr));

	if (lp->features & XAE_FEATURE_DMA_64BIT)
		axienet_dma_out32(lp, reg + 4, upper_32_bits(addr));
}

static void desc_set_phys_addr(struct axienet_local *lp, dma_addr_t addr,
			       struct axidma_bd *desc)
{
@@ -2061,6 +2037,10 @@ static int axienet_probe(struct platform_device *pdev)
			iowrite32(0x0, desc);
		}
	}
	if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) {
		dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n");
		goto cleanup_clk;
	}

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