diff mbox series

[net-next,1/2] net: axienet: make the 64b addresable DMA depends on 64b archectures

Message ID 20220613034202.3777248-2-andy.chiu@sifive.com (mailing list archive)
State New, archived
Headers show
Series net: axienet: fix DMA Tx error | expand

Commit Message

Andy Chiu June 13, 2022, 3:42 a.m. UTC
Currently it is not safe to config the IP as 64-bit addressable on 32-bit
archectures, which cannot perform a double-word store on its descriptor
pointers. The pointer is 64-bit wide if the IP is configured as 64-bit,
and the device would process the partially updated pointer on some
states if the pointer was updated via two store-words. To prevent such
condition, we force a probe fail if we discover that the IP has 64-bit
capability but it is not running on a 64-Bit kernel.

This is a series of patch (1/2). The next patch must be applied in order
to make 64b DMA safe on 64b archectures.

Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
Reported-by: Max Hsu <max.hsu@sifive.com>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h  | 36 +++++++++++++++++++
 .../net/ethernet/xilinx/xilinx_axienet_main.c | 28 +++------------
 2 files changed, 40 insertions(+), 24 deletions(-)

Comments

Andy Chiu June 13, 2022, 8:18 a.m. UTC | #1
Reviewed-by: Greentime Hu <greentime.hu@sifive.com>

On Mon, Jun 13, 2022 at 11:45 AM Andy Chiu <andy.chiu@sifive.com> wrote:
>
> Currently it is not safe to config the IP as 64-bit addressable on 32-bit
> archectures, which cannot perform a double-word store on its descriptor
> pointers. The pointer is 64-bit wide if the IP is configured as 64-bit,
> and the device would process the partially updated pointer on some
> states if the pointer was updated via two store-words. To prevent such
> condition, we force a probe fail if we discover that the IP has 64-bit
> capability but it is not running on a 64-Bit kernel.
>
> This is a series of patch (1/2). The next patch must be applied in order
> to make 64b DMA safe on 64b archectures.
>
> Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
> Reported-by: Max Hsu <max.hsu@sifive.com>
> ---
>  drivers/net/ethernet/xilinx/xilinx_axienet.h  | 36 +++++++++++++++++++
>  .../net/ethernet/xilinx/xilinx_axienet_main.c | 28 +++------------
>  2 files changed, 40 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> index 4225efbeda3d..6c95676ba172 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
> @@ -547,6 +547,42 @@ 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
> +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));
> +}
> +
> +#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);
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> index 93c9f305bba4..fa7bcd2c1892 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> @@ -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) {
> --
> 2.36.0
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 4225efbeda3d..6c95676ba172 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -547,6 +547,42 @@  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
+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));
+}
+
+#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);
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 93c9f305bba4..fa7bcd2c1892 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -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) {