netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/11] stmmac: Add Loongson platform support
@ 2023-08-22  9:40 Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks Feiyang Chen
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Add and extend stmmac functions and macros for Loongson DWMAC.
Add LS7A support and GNET support for dwmac_loongson.

Split the code for extended GMAC (dwegmac) from dwmac1000, try
not to mix up registers and core id.

Some features of Loongson platforms are bound to the GMAC_VERSION
register. We have to read its value in dwmac-loongson in order to
get the correct channel number and DMA configuration.

The current usage of stmmac_request_irq_multi_msi() is limited to
dwmac-intel. While it appears that setting irq_flags might not be
necessary for dwmac-intel, it should be configured for other drivers
like dwmac-loongson. I've observed many drivers directly setting
irq_flags within their probe functions or data structures without
referencing the DT. Since I'm unsure about the proper handling of
irq_flags, I've chosen to retain the code as-is.

Feiyang Chen (11):
  net: stmmac: Pass stmmac_priv and chan in some callbacks
  stmmac: dwmac1000: Add 64-bit DMA support
  stmmac: Add extended GMAC support for Loongson platforms
  net: stmmac: Allow platforms to set irq_flags
  net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe()
  net: stmmac: dwmac-loongson: Add LS7A support
  net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support
  net: stmmac: dwegmac: Fix channel numbers
  net: stmmac: dwmac-loongson: Disable flow control for GMAC
  net: stmmac: dwegmac: Disable coe
  net: stmmac: dwmac-loongson: Add GNET support

 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 .../net/ethernet/stmicro/stmmac/chain_mode.c  |  29 +-
 drivers/net/ethernet/stmicro/stmmac/common.h  |   3 +
 drivers/net/ethernet/stmicro/stmmac/descs.h   |   7 +
 .../net/ethernet/stmicro/stmmac/descs_com.h   |  47 +-
 drivers/net/ethernet/stmicro/stmmac/dwegmac.h | 332 +++++++++++
 .../ethernet/stmicro/stmmac/dwegmac_core.c    | 552 ++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/dwegmac_dma.c | 522 +++++++++++++++++
 .../net/ethernet/stmicro/stmmac/dwegmac_dma.h | 190 ++++++
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 338 ++++++++---
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  22 +-
 .../ethernet/stmicro/stmmac/dwmac1000_core.c  |   9 +-
 .../ethernet/stmicro/stmmac/dwmac1000_dma.c   |  54 +-
 .../ethernet/stmicro/stmmac/dwmac100_core.c   |   9 +-
 .../ethernet/stmicro/stmmac/dwmac100_dma.c    |   2 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c |  11 +-
 .../ethernet/stmicro/stmmac/dwmac4_descs.c    |  17 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |   8 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |   2 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |   2 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  22 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |   5 +-
 .../ethernet/stmicro/stmmac/dwxgmac2_core.c   |  11 +-
 .../ethernet/stmicro/stmmac/dwxgmac2_descs.c  |  17 +-
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    |  10 +-
 .../net/ethernet/stmicro/stmmac/enh_desc.c    |  38 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.c    |  66 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  73 ++-
 .../net/ethernet/stmicro/stmmac/norm_desc.c   |  17 +-
 .../net/ethernet/stmicro/stmmac/ring_mode64.c | 158 +++++
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |   8 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  34 +-
 include/linux/stmmac.h                        |  11 +
 33 files changed, 2410 insertions(+), 218 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac.h
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode64.c

-- 
2.39.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22 10:03   ` Russell King (Oracle)
  2023-08-22  9:40 ` [PATCH v4 02/11] stmmac: dwmac1000: Add 64-bit DMA support Feiyang Chen
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Loongson GMAC and GNET have many extended features. To prepare for
that, pass stmmac_priv and chan to more callbacks, and adjust the
callbacks accordingly.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../net/ethernet/stmicro/stmmac/chain_mode.c  |  5 +-
 .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 22 +++---
 .../ethernet/stmicro/stmmac/dwmac1000_core.c  |  9 ++-
 .../ethernet/stmicro/stmmac/dwmac1000_dma.c   |  8 ++-
 .../ethernet/stmicro/stmmac/dwmac100_core.c   |  9 ++-
 .../ethernet/stmicro/stmmac/dwmac100_dma.c    |  2 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_core.c | 11 +--
 .../ethernet/stmicro/stmmac/dwmac4_descs.c    | 17 ++---
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |  8 ++-
 .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |  2 +-
 .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |  2 +-
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  5 +-
 .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |  5 +-
 .../ethernet/stmicro/stmmac/dwxgmac2_core.c   | 11 +--
 .../ethernet/stmicro/stmmac/dwxgmac2_descs.c  | 17 ++---
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    | 10 +--
 .../net/ethernet/stmicro/stmmac/enh_desc.c    | 17 ++---
 drivers/net/ethernet/stmicro/stmmac/hwif.c    |  2 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h    | 71 ++++++++++---------
 .../net/ethernet/stmicro/stmmac/norm_desc.c   | 17 ++---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  6 +-
 21 files changed, 146 insertions(+), 110 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index fb55efd52240..a95866871f3e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -95,8 +95,9 @@ static unsigned int is_jumbo_frm(int len, int enh_desc)
 	return ret;
 }
 
-static void init_dma_chain(void *des, dma_addr_t phy_addr,
-				  unsigned int size, unsigned int extend_desc)
+static void init_dma_chain(struct stmmac_priv *priv, void *des,
+			   dma_addr_t phy_addr, unsigned int size,
+			   unsigned int extend_desc)
 {
 	/*
 	 * In chained mode the des3 points to the next element in the ring.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 1e714380d125..59ea67cc7e6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -282,7 +282,7 @@ static const struct emac_variant emac_variant_h6 = {
 /* sun8i_dwmac_dma_reset() - reset the EMAC
  * Called from stmmac via stmmac_dma_ops->reset
  */
-static int sun8i_dwmac_dma_reset(void __iomem *ioaddr)
+static int sun8i_dwmac_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
 {
 	writel(0, ioaddr + EMAC_RX_CTL1);
 	writel(0, ioaddr + EMAC_TX_CTL1);
@@ -297,7 +297,7 @@ static int sun8i_dwmac_dma_reset(void __iomem *ioaddr)
 /* sun8i_dwmac_dma_init() - initialize the EMAC
  * Called from stmmac via stmmac_dma_ops->init
  */
-static void sun8i_dwmac_dma_init(void __iomem *ioaddr,
+static void sun8i_dwmac_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 struct stmmac_dma_cfg *dma_cfg, int atds)
 {
 	writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN);
@@ -394,7 +394,8 @@ static void sun8i_dwmac_dma_start_tx(struct stmmac_priv *priv,
 	writel(v, ioaddr + EMAC_TX_CTL1);
 }
 
-static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr)
+static void sun8i_dwmac_enable_dma_transmission(struct stmmac_priv *priv,
+						void __iomem *ioaddr, u32 chan)
 {
 	u32 v;
 
@@ -636,7 +637,8 @@ static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable)
  * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST
  * If addr is NULL, clear the slot
  */
-static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw,
+static void sun8i_dwmac_set_umac_addr(struct stmmac_priv *priv,
+				      struct mac_device_info *hw,
 				      const unsigned char *addr,
 				      unsigned int reg_n)
 {
@@ -657,7 +659,8 @@ static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw,
 	}
 }
 
-static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw,
+static void sun8i_dwmac_get_umac_addr(struct stmmac_priv *priv,
+				      struct mac_device_info *hw,
 				      unsigned char *addr,
 				      unsigned int reg_n)
 {
@@ -680,7 +683,8 @@ static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw)
 	return 1;
 }
 
-static void sun8i_dwmac_set_filter(struct mac_device_info *hw,
+static void sun8i_dwmac_set_filter(struct stmmac_priv *priv,
+				   struct mac_device_info *hw,
 				   struct net_device *dev)
 {
 	void __iomem *ioaddr = hw->pcsr;
@@ -698,13 +702,13 @@ static void sun8i_dwmac_set_filter(struct mac_device_info *hw,
 	} else if (macaddrs <= hw->unicast_filter_entries) {
 		if (!netdev_mc_empty(dev)) {
 			netdev_for_each_mc_addr(ha, dev) {
-				sun8i_dwmac_set_umac_addr(hw, ha->addr, i);
+				sun8i_dwmac_set_umac_addr(priv, hw, ha->addr, i);
 				i++;
 			}
 		}
 		if (!netdev_uc_empty(dev)) {
 			netdev_for_each_uc_addr(ha, dev) {
-				sun8i_dwmac_set_umac_addr(hw, ha->addr, i);
+				sun8i_dwmac_set_umac_addr(priv, hw, ha->addr, i);
 				i++;
 			}
 		}
@@ -716,7 +720,7 @@ static void sun8i_dwmac_set_filter(struct mac_device_info *hw,
 
 	/* Disable unused address filter slots */
 	while (i < hw->unicast_filter_entries)
-		sun8i_dwmac_set_umac_addr(hw, NULL, i++);
+		sun8i_dwmac_set_umac_addr(priv, hw, NULL, i++);
 
 	writel(v, ioaddr + EMAC_RX_FRM_FLT);
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 3927609abc44..b52793edf62f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -94,7 +94,8 @@ static void dwmac1000_dump_regs(struct mac_device_info *hw, u32 *reg_space)
 		reg_space[i] = readl(ioaddr + i * 4);
 }
 
-static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
+static void dwmac1000_set_umac_addr(struct stmmac_priv *priv,
+				    struct mac_device_info *hw,
 				    const unsigned char *addr,
 				    unsigned int reg_n)
 {
@@ -103,7 +104,8 @@ static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
 			    GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
+static void dwmac1000_get_umac_addr(struct stmmac_priv *priv,
+				    struct mac_device_info *hw,
 				    unsigned char *addr,
 				    unsigned int reg_n)
 {
@@ -137,7 +139,8 @@ static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
 		       ioaddr + GMAC_EXTHASH_BASE + regs * 4);
 }
 
-static void dwmac1000_set_filter(struct mac_device_info *hw,
+static void dwmac1000_set_filter(struct stmmac_priv *priv,
+				 struct mac_device_info *hw,
 				 struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index daf79cdbd3ec..ce0e6ca6f3a2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -16,7 +16,8 @@
 #include "dwmac1000.h"
 #include "dwmac_dma.h"
 
-static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
+static void dwmac1000_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
+			      struct stmmac_axi *axi)
 {
 	u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
 	int i;
@@ -70,7 +71,7 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
 	writel(value, ioaddr + DMA_AXI_BUS_MODE);
 }
 
-static void dwmac1000_dma_init(void __iomem *ioaddr,
+static void dwmac1000_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 			       struct stmmac_dma_cfg *dma_cfg, int atds)
 {
 	u32 value = readl(ioaddr + DMA_BUS_MODE);
@@ -223,7 +224,8 @@ static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv,
 				readl(ioaddr + DMA_BUS_MODE + i * 4);
 }
 
-static int dwmac1000_get_hw_feature(void __iomem *ioaddr,
+static int dwmac1000_get_hw_feature(struct stmmac_priv *priv,
+				    void __iomem *ioaddr,
 				    struct dma_features *dma_cap)
 {
 	u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index a6e8d7bd9588..c03623edeb75 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -59,7 +59,8 @@ static int dwmac100_irq_status(struct mac_device_info *hw,
 	return 0;
 }
 
-static void dwmac100_set_umac_addr(struct mac_device_info *hw,
+static void dwmac100_set_umac_addr(struct stmmac_priv *priv,
+				   struct mac_device_info *hw,
 				   const unsigned char *addr,
 				   unsigned int reg_n)
 {
@@ -67,7 +68,8 @@ static void dwmac100_set_umac_addr(struct mac_device_info *hw,
 	stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_get_umac_addr(struct mac_device_info *hw,
+static void dwmac100_get_umac_addr(struct stmmac_priv *priv,
+				   struct mac_device_info *hw,
 				   unsigned char *addr,
 				   unsigned int reg_n)
 {
@@ -75,7 +77,8 @@ static void dwmac100_get_umac_addr(struct mac_device_info *hw,
 	stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_set_filter(struct mac_device_info *hw,
+static void dwmac100_set_filter(struct stmmac_priv *priv,
+				struct mac_device_info *hw,
 				struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index 1c32b1788f02..e6ae230fa453 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -18,7 +18,7 @@
 #include "dwmac100.h"
 #include "dwmac_dma.h"
 
-static void dwmac100_dma_init(void __iomem *ioaddr,
+static void dwmac100_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 			      struct stmmac_dma_cfg *dma_cfg, int atds)
 {
 	/* Enable Application Access by writing to DMA CSR0 */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 03b1c5a97826..536928ccacf9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -330,7 +330,8 @@ static void dwmac4_pmt(struct mac_device_info *hw, unsigned long mode)
 	writel(pmt, ioaddr + GMAC_PMT);
 }
 
-static void dwmac4_set_umac_addr(struct mac_device_info *hw,
+static void dwmac4_set_umac_addr(struct stmmac_priv *priv,
+				 struct mac_device_info *hw,
 				 const unsigned char *addr, unsigned int reg_n)
 {
 	void __iomem *ioaddr = hw->pcsr;
@@ -339,7 +340,8 @@ static void dwmac4_set_umac_addr(struct mac_device_info *hw,
 				   GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac4_get_umac_addr(struct mac_device_info *hw,
+static void dwmac4_get_umac_addr(struct stmmac_priv *priv,
+				 struct mac_device_info *hw,
 				 unsigned char *addr, unsigned int reg_n)
 {
 	void __iomem *ioaddr = hw->pcsr;
@@ -588,7 +590,8 @@ static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev,
 	}
 }
 
-static void dwmac4_set_filter(struct mac_device_info *hw,
+static void dwmac4_set_filter(struct stmmac_priv *priv,
+			      struct mac_device_info *hw,
 			      struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
@@ -664,7 +667,7 @@ static void dwmac4_set_filter(struct mac_device_info *hw,
 		int reg = 1;
 
 		netdev_for_each_uc_addr(ha, dev) {
-			dwmac4_set_umac_addr(hw, ha->addr, reg);
+			dwmac4_set_umac_addr(priv, hw, ha->addr, reg);
 			reg++;
 		}
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 6a011d8633e8..cf3ba470256f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -175,7 +175,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
 	return ret;
 }
 
-static int dwmac4_rd_get_tx_len(struct dma_desc *p)
+static int dwmac4_rd_get_tx_len(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	return (le32_to_cpu(p->des2) & TDES2_BUFFER1_SIZE_MASK);
 }
@@ -296,8 +296,8 @@ static int dwmac4_wrback_get_rx_timestamp_status(void *desc, void *next_desc,
 	return 0;
 }
 
-static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
-				   int mode, int end, int bfsize)
+static void dwmac4_rd_init_rx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				   int disable_rx_ic, int mode, int end, int bfsize)
 {
 	dwmac4_set_rx_owner(p, disable_rx_ic);
 }
@@ -310,9 +310,9 @@ static void dwmac4_rd_init_tx_desc(struct dma_desc *p, int mode, int end)
 	p->des3 = 0;
 }
 
-static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-				      bool csum_flag, int mode, bool tx_own,
-				      bool ls, unsigned int tot_pkt_len)
+static void dwmac4_rd_prepare_tx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				      int is_fs, int len, bool csum_flag, int mode,
+				      bool tx_own, bool ls, unsigned int tot_pkt_len)
 {
 	unsigned int tdes3 = le32_to_cpu(p->des3);
 
@@ -462,13 +462,14 @@ static void dwmac4_set_mss_ctxt(struct dma_desc *p, unsigned int mss)
 	p->des3 = cpu_to_le32(TDES3_CONTEXT_TYPE | TDES3_CTXT_TCMSSV);
 }
 
-static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
+static void dwmac4_set_addr(struct stmmac_priv *priv, struct dma_desc *p,
+			    dma_addr_t addr)
 {
 	p->des0 = cpu_to_le32(lower_32_bits(addr));
 	p->des1 = cpu_to_le32(upper_32_bits(addr));
 }
 
-static void dwmac4_clear(struct dma_desc *p)
+static void dwmac4_clear(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	p->des0 = 0;
 	p->des1 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 84d3a8551b03..97dad00dc850 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -15,7 +15,8 @@
 #include "dwmac4_dma.h"
 #include "stmmac.h"
 
-static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
+static void dwmac4_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
+			   struct stmmac_axi *axi)
 {
 	u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
 	int i;
@@ -152,7 +153,7 @@ static void dwmac410_dma_init_channel(struct stmmac_priv *priv,
 	       ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
 }
 
-static void dwmac4_dma_init(void __iomem *ioaddr,
+static void dwmac4_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 			    struct stmmac_dma_cfg *dma_cfg, int atds)
 {
 	u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
@@ -374,7 +375,8 @@ static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv,
 	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel));
 }
 
-static int dwmac4_get_hw_feature(void __iomem *ioaddr,
+static int dwmac4_get_hw_feature(struct stmmac_priv *priv,
+				 void __iomem *ioaddr,
 				 struct dma_features *dma_cap)
 {
 	u32 hw_cap = readl(ioaddr + GMAC_HW_FEATURE0);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 358e7dcb6a9a..aaab5ab38373 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -231,7 +231,7 @@ static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs,
 #define DMA_CHAN0_DBG_STAT_RPS		GENMASK(11, 8)
 #define DMA_CHAN0_DBG_STAT_RPS_SHIFT	8
 
-int dwmac4_dma_reset(void __iomem *ioaddr);
+int dwmac4_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr);
 void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
 			   u32 chan, bool rx, bool tx);
 void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 03ceb6a94073..58d5f23df21e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -13,7 +13,7 @@
 #include "dwmac4.h"
 #include "stmmac.h"
 
-int dwmac4_dma_reset(void __iomem *ioaddr)
+int dwmac4_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
 {
 	u32 value = readl(ioaddr + DMA_BUS_MODE);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 72672391675f..77141391bd2f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -152,7 +152,8 @@
 #define NUM_DWMAC1000_DMA_REGS	23
 #define NUM_DWMAC4_DMA_REGS	27
 
-void dwmac_enable_dma_transmission(void __iomem *ioaddr);
+void dwmac_enable_dma_transmission(struct stmmac_priv *priv,
+				   void __iomem *ioaddr, u32 chan);
 void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
 			  u32 chan, bool rx, bool tx);
 void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -167,6 +168,6 @@ void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
 		       u32 chan);
 int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
 			struct stmmac_extra_stats *x, u32 chan, u32 dir);
-int dwmac_dma_reset(void __iomem *ioaddr);
+int dwmac_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr);
 
 #endif /* __DWMAC_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 0b6f999a8305..053a8af6d0e1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -13,7 +13,7 @@
 
 #define GMAC_HI_REG_AE		0x80000000
 
-int dwmac_dma_reset(void __iomem *ioaddr)
+int dwmac_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
 {
 	u32 value = readl(ioaddr + DMA_BUS_MODE);
 
@@ -27,7 +27,8 @@ int dwmac_dma_reset(void __iomem *ioaddr)
 }
 
 /* CSR1 enables the transmit DMA to check for new descriptor */
-void dwmac_enable_dma_transmission(void __iomem *ioaddr)
+void dwmac_enable_dma_transmission(struct stmmac_priv *priv,
+				   void __iomem *ioaddr, u32 chan)
 {
 	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index a0c2ef8bb0ac..640c1b4a0c14 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -337,7 +337,8 @@ static void dwxgmac2_pmt(struct mac_device_info *hw, unsigned long mode)
 	writel(val, ioaddr + XGMAC_PMT);
 }
 
-static void dwxgmac2_set_umac_addr(struct mac_device_info *hw,
+static void dwxgmac2_set_umac_addr(struct stmmac_priv *priv,
+				   struct mac_device_info *hw,
 				   const unsigned char *addr,
 				   unsigned int reg_n)
 {
@@ -351,7 +352,8 @@ static void dwxgmac2_set_umac_addr(struct mac_device_info *hw,
 	writel(value, ioaddr + XGMAC_ADDRx_LOW(reg_n));
 }
 
-static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
+static void dwxgmac2_get_umac_addr(struct stmmac_priv *priv,
+				   struct mac_device_info *hw,
 				   unsigned char *addr, unsigned int reg_n)
 {
 	void __iomem *ioaddr = hw->pcsr;
@@ -440,7 +442,8 @@ static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
 		writel(mcfilterbits[regs], ioaddr + XGMAC_HASH_TABLE(regs));
 }
 
-static void dwxgmac2_set_filter(struct mac_device_info *hw,
+static void dwxgmac2_set_filter(struct stmmac_priv *priv,
+				struct mac_device_info *hw,
 				struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
@@ -485,7 +488,7 @@ static void dwxgmac2_set_filter(struct mac_device_info *hw,
 		int reg = 1;
 
 		netdev_for_each_uc_addr(ha, dev) {
-			dwxgmac2_set_umac_addr(hw, ha->addr, reg);
+			dwxgmac2_set_umac_addr(priv, hw, ha->addr, reg);
 			reg++;
 		}
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 13c347ee8be9..e6fb47563fc0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -41,7 +41,7 @@ static int dwxgmac2_get_rx_status(struct net_device_stats *stats,
 	return good_frame;
 }
 
-static int dwxgmac2_get_tx_len(struct dma_desc *p)
+static int dwxgmac2_get_tx_len(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
 }
@@ -128,8 +128,8 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
 	return !ret;
 }
 
-static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
-				  int mode, int end, int bfsize)
+static void dwxgmac2_init_rx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				  int disable_rx_ic, int mode, int end, int bfsize)
 {
 	dwxgmac2_set_rx_owner(p, disable_rx_ic);
 }
@@ -142,9 +142,9 @@ static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
 	p->des3 = 0;
 }
 
-static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-				     bool csum_flag, int mode, bool tx_own,
-				     bool ls, unsigned int tot_pkt_len)
+static void dwxgmac2_prepare_tx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				     int is_fs, int len, bool csum_flag, int mode,
+				     bool tx_own, bool ls, unsigned int tot_pkt_len)
 {
 	unsigned int tdes3 = le32_to_cpu(p->des3);
 
@@ -241,13 +241,14 @@ static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
 	p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
 }
 
-static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
+static void dwxgmac2_set_addr(struct stmmac_priv *priv, struct dma_desc *p,
+			      dma_addr_t addr)
 {
 	p->des0 = cpu_to_le32(lower_32_bits(addr));
 	p->des1 = cpu_to_le32(upper_32_bits(addr));
 }
 
-static void dwxgmac2_clear(struct dma_desc *p)
+static void dwxgmac2_clear(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	p->des0 = 0;
 	p->des1 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 070bd912580b..5cbee9ed27f0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -8,7 +8,7 @@
 #include "stmmac.h"
 #include "dwxgmac2.h"
 
-static int dwxgmac2_dma_reset(void __iomem *ioaddr)
+static int dwxgmac2_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
 {
 	u32 value = readl(ioaddr + XGMAC_DMA_MODE);
 
@@ -19,7 +19,7 @@ static int dwxgmac2_dma_reset(void __iomem *ioaddr)
 				  !(value & XGMAC_SWR), 0, 100000);
 }
 
-static void dwxgmac2_dma_init(void __iomem *ioaddr,
+static void dwxgmac2_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 			      struct stmmac_dma_cfg *dma_cfg, int atds)
 {
 	u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
@@ -81,7 +81,8 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
 	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
 }
 
-static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
+static void dwxgmac2_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
+			     struct stmmac_axi *axi)
 {
 	u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
 	int i;
@@ -384,7 +385,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
 	return ret;
 }
 
-static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
+static int dwxgmac2_get_hw_feature(struct stmmac_priv *priv,
+				   void __iomem *ioaddr,
 				   struct dma_features *dma_cap)
 {
 	u32 hw_cap;
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index a91d8f13a931..1932a3a8e03c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -79,7 +79,7 @@ static int enh_desc_get_tx_status(struct net_device_stats *stats,
 	return ret;
 }
 
-static int enh_desc_get_tx_len(struct dma_desc *p)
+static int enh_desc_get_tx_len(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
 }
@@ -255,8 +255,8 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
 	return ret;
 }
 
-static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
-				  int mode, int end, int bfsize)
+static void enh_desc_init_rx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				  int disable_rx_ic, int mode, int end, int bfsize)
 {
 	int bfsize1;
 
@@ -314,9 +314,9 @@ static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
 		enh_desc_end_tx_desc_on_ring(p, ter);
 }
 
-static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-				     bool csum_flag, int mode, bool tx_own,
-				     bool ls, unsigned int tot_pkt_len)
+static void enh_desc_prepare_tx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				     int is_fs, int len, bool csum_flag, int mode,
+				     bool tx_own, bool ls, unsigned int tot_pkt_len)
 {
 	unsigned int tdes0 = le32_to_cpu(p->des0);
 
@@ -441,12 +441,13 @@ static void enh_desc_display_ring(void *head, unsigned int size, bool rx,
 	pr_info("\n");
 }
 
-static void enh_desc_set_addr(struct dma_desc *p, dma_addr_t addr)
+static void enh_desc_set_addr(struct stmmac_priv *priv, struct dma_desc *p,
+			      dma_addr_t addr)
 {
 	p->des2 = cpu_to_le32(addr);
 }
 
-static void enh_desc_clear(struct dma_desc *p)
+static void enh_desc_clear(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	p->des2 = 0;
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index b8ba8f2d8041..93cead5613e3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -97,7 +97,7 @@ int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
 	if (plat && plat->fix_soc_reset)
 		return plat->fix_soc_reset(plat, ioaddr);
 
-	return stmmac_do_callback(priv, dma, reset, ioaddr);
+	return stmmac_do_callback(priv, dma, reset, priv, ioaddr);
 }
 
 static const struct stmmac_hwif_entry {
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 6ee7cf07cfd7..00be9a7003c8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -35,14 +35,14 @@ struct dma_edesc;
 /* Descriptors helpers */
 struct stmmac_desc_ops {
 	/* DMA RX descriptor ring initialization */
-	void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode,
-			int end, int bfsize);
+	void (*init_rx_desc)(struct stmmac_priv *priv, struct dma_desc *p,
+			int disable_rx_ic, int mode, int end, int bfsize);
 	/* DMA TX descriptor ring initialization */
 	void (*init_tx_desc)(struct dma_desc *p, int mode, int end);
 	/* Invoked by the xmit function to prepare the tx descriptor */
-	void (*prepare_tx_desc)(struct dma_desc *p, int is_fs, int len,
-			bool csum_flag, int mode, bool tx_own, bool ls,
-			unsigned int tot_pkt_len);
+	void (*prepare_tx_desc)(struct stmmac_priv *priv, struct dma_desc *p,
+			int is_fs, int len, bool csum_flag, int mode,
+			bool tx_own, bool ls, unsigned int tot_pkt_len);
 	void (*prepare_tso_tx_desc)(struct dma_desc *p, int is_fs, int len1,
 			int len2, bool tx_own, bool ls, unsigned int tcphdrlen,
 			unsigned int tcppayloadlen);
@@ -61,7 +61,7 @@ struct stmmac_desc_ops {
 			 struct stmmac_extra_stats *x,
 			 struct dma_desc *p, void __iomem *ioaddr);
 	/* Get the buffer size from the descriptor */
-	int (*get_tx_len)(struct dma_desc *p);
+	int (*get_tx_len)(struct stmmac_priv *priv, struct dma_desc *p);
 	/* Handle extra events on specific interrupts hw dependent */
 	void (*set_rx_owner)(struct dma_desc *p, int disable_rx_ic);
 	/* Get the receive frame size */
@@ -87,9 +87,10 @@ struct stmmac_desc_ops {
 	/* set MSS via context descriptor */
 	void (*set_mss)(struct dma_desc *p, unsigned int mss);
 	/* set descriptor skbuff address */
-	void (*set_addr)(struct dma_desc *p, dma_addr_t addr);
+	void (*set_addr)(struct stmmac_priv *priv, struct dma_desc *p,
+			dma_addr_t addr);
 	/* clear descriptor */
-	void (*clear)(struct dma_desc *p);
+	void (*clear)(struct stmmac_priv *priv, struct dma_desc *p);
 	/* RSS */
 	int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
 			   enum pkt_hash_types *type);
@@ -103,11 +104,11 @@ struct stmmac_desc_ops {
 };
 
 #define stmmac_init_rx_desc(__priv, __args...) \
-	stmmac_do_void_callback(__priv, desc, init_rx_desc, __args)
+	stmmac_do_void_callback(__priv, desc, init_rx_desc, __priv, __args)
 #define stmmac_init_tx_desc(__priv, __args...) \
 	stmmac_do_void_callback(__priv, desc, init_tx_desc, __args)
 #define stmmac_prepare_tx_desc(__priv, __args...) \
-	stmmac_do_void_callback(__priv, desc, prepare_tx_desc, __args)
+	stmmac_do_void_callback(__priv, desc, prepare_tx_desc, __priv, __args)
 #define stmmac_prepare_tso_tx_desc(__priv, __args...) \
 	stmmac_do_void_callback(__priv, desc, prepare_tso_tx_desc, __args)
 #define stmmac_set_tx_owner(__priv, __args...) \
@@ -123,7 +124,7 @@ struct stmmac_desc_ops {
 #define stmmac_tx_status(__priv, __args...) \
 	stmmac_do_callback(__priv, desc, tx_status, __args)
 #define stmmac_get_tx_len(__priv, __args...) \
-	stmmac_do_callback(__priv, desc, get_tx_len, __args)
+	stmmac_do_callback(__priv, desc, get_tx_len, __priv, __args)
 #define stmmac_set_rx_owner(__priv, __args...) \
 	stmmac_do_void_callback(__priv, desc, set_rx_owner, __args)
 #define stmmac_get_rx_frame_len(__priv, __args...) \
@@ -145,9 +146,9 @@ struct stmmac_desc_ops {
 #define stmmac_set_mss(__priv, __args...) \
 	stmmac_do_void_callback(__priv, desc, set_mss, __args)
 #define stmmac_set_desc_addr(__priv, __args...) \
-	stmmac_do_void_callback(__priv, desc, set_addr, __args)
+	stmmac_do_void_callback(__priv, desc, set_addr, __priv, __args)
 #define stmmac_clear_desc(__priv, __args...) \
-	stmmac_do_void_callback(__priv, desc, clear, __args)
+	stmmac_do_void_callback(__priv, desc, clear, __priv, __args)
 #define stmmac_get_rx_hash(__priv, __args...) \
 	stmmac_do_callback(__priv, desc, get_rx_hash, __args)
 #define stmmac_get_rx_header_len(__priv, __args...) \
@@ -169,9 +170,9 @@ struct dma_features;
 /* Specific DMA helpers */
 struct stmmac_dma_ops {
 	/* DMA core initialization */
-	int (*reset)(void __iomem *ioaddr);
-	void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg,
-		     int atds);
+	int (*reset)(struct stmmac_priv *priv, void __iomem *ioaddr);
+	void (*init)(struct stmmac_priv *priv, void __iomem *ioaddr,
+		     struct stmmac_dma_cfg *dma_cfg, int atds);
 	void (*init_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			  struct stmmac_dma_cfg *dma_cfg, u32 chan);
 	void (*init_rx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -181,7 +182,8 @@ struct stmmac_dma_ops {
 			     struct stmmac_dma_cfg *dma_cfg,
 			     dma_addr_t phy, u32 chan);
 	/* Configure the AXI Bus Mode Register */
-	void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
+	void (*axi)(struct stmmac_priv *priv, void __iomem *ioaddr,
+		    struct stmmac_axi *axi);
 	/* Dump DMA registers */
 	void (*dump_regs)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			  u32 *reg_space);
@@ -194,7 +196,8 @@ struct stmmac_dma_ops {
 	void (*dma_diagnostic_fr)(struct net_device_stats *stats,
 				  struct stmmac_extra_stats *x,
 				  void __iomem *ioaddr);
-	void (*enable_dma_transmission) (void __iomem *ioaddr);
+	void (*enable_dma_transmission)(struct stmmac_priv *priv,
+					void __iomem *ioaddr, u32 chan);
 	void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			       u32 chan, bool rx, bool tx);
 	void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -210,7 +213,7 @@ struct stmmac_dma_ops {
 	int (*dma_interrupt)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			     struct stmmac_extra_stats *x, u32 chan, u32 dir);
 	/* If supported then get the optional core features */
-	int (*get_hw_feature)(void __iomem *ioaddr,
+	int (*get_hw_feature)(struct stmmac_priv *priv, void __iomem *ioaddr,
 			      struct dma_features *dma_cap);
 	/* Program the HW RX Watchdog */
 	void (*rx_watchdog)(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -236,7 +239,7 @@ struct stmmac_dma_ops {
 };
 
 #define stmmac_dma_init(__priv, __args...) \
-	stmmac_do_void_callback(__priv, dma, init, __args)
+	stmmac_do_void_callback(__priv, dma, init, __priv, __args)
 #define stmmac_init_chan(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, init_chan, __priv, __args)
 #define stmmac_init_rx_chan(__priv, __args...) \
@@ -244,7 +247,7 @@ struct stmmac_dma_ops {
 #define stmmac_init_tx_chan(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, init_tx_chan, __priv, __args)
 #define stmmac_axi(__priv, __args...) \
-	stmmac_do_void_callback(__priv, dma, axi, __args)
+	stmmac_do_void_callback(__priv, dma, axi, __priv, __args)
 #define stmmac_dump_dma_regs(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, dump_regs, __priv, __args)
 #define stmmac_dma_rx_mode(__priv, __args...) \
@@ -254,7 +257,7 @@ struct stmmac_dma_ops {
 #define stmmac_dma_diagnostic_fr(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, dma_diagnostic_fr, __args)
 #define stmmac_enable_dma_transmission(__priv, __args...) \
-	stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __args)
+	stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __priv, __args)
 #define stmmac_enable_dma_irq(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, enable_dma_irq, __priv, __args)
 #define stmmac_disable_dma_irq(__priv, __args...) \
@@ -270,7 +273,7 @@ struct stmmac_dma_ops {
 #define stmmac_dma_interrupt_status(__priv, __args...) \
 	stmmac_do_callback(__priv, dma, dma_interrupt, __priv, __args)
 #define stmmac_get_hw_feature(__priv, __args...) \
-	stmmac_do_callback(__priv, dma, get_hw_feature, __args)
+	stmmac_do_callback(__priv, dma, get_hw_feature, __priv, __args)
 #define stmmac_rx_watchdog(__priv, __args...) \
 	stmmac_do_void_callback(__priv, dma, rx_watchdog, __priv, __args)
 #define stmmac_set_tx_ring_len(__priv, __args...) \
@@ -340,17 +343,21 @@ struct stmmac_ops {
 	int (*host_mtl_irq_status)(struct stmmac_priv *priv,
 				   struct mac_device_info *hw, u32 chan);
 	/* Multicast filter setting */
-	void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
+	void (*set_filter)(struct stmmac_priv *priv, struct mac_device_info *hw,
+			   struct net_device *dev);
 	/* Flow control setting */
 	void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
 			  unsigned int fc, unsigned int pause_time, u32 tx_cnt);
 	/* Set power management mode (e.g. magic frame) */
 	void (*pmt)(struct mac_device_info *hw, unsigned long mode);
 	/* Set/Get Unicast MAC addresses */
-	void (*set_umac_addr)(struct mac_device_info *hw,
+	void (*set_umac_addr)(struct stmmac_priv *priv,
+			      struct mac_device_info *hw,
 			      const unsigned char *addr,
 			      unsigned int reg_n);
-	void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
+	void (*get_umac_addr)(struct stmmac_priv *priv,
+			      struct mac_device_info *hw,
+			      unsigned char *addr,
 			      unsigned int reg_n);
 	void (*set_eee_mode)(struct mac_device_info *hw,
 			     bool en_tx_lpi_clockgating);
@@ -452,15 +459,15 @@ struct stmmac_ops {
 #define stmmac_host_mtl_irq_status(__priv, __args...) \
 	stmmac_do_callback(__priv, mac, host_mtl_irq_status, __priv, __args)
 #define stmmac_set_filter(__priv, __args...) \
-	stmmac_do_void_callback(__priv, mac, set_filter, __args)
+	stmmac_do_void_callback(__priv, mac, set_filter, __priv, __args)
 #define stmmac_flow_ctrl(__priv, __args...) \
 	stmmac_do_void_callback(__priv, mac, flow_ctrl, __args)
 #define stmmac_pmt(__priv, __args...) \
 	stmmac_do_void_callback(__priv, mac, pmt, __args)
 #define stmmac_set_umac_addr(__priv, __args...) \
-	stmmac_do_void_callback(__priv, mac, set_umac_addr, __args)
+	stmmac_do_void_callback(__priv, mac, set_umac_addr, __priv, __args)
 #define stmmac_get_umac_addr(__priv, __args...) \
-	stmmac_do_void_callback(__priv, mac, get_umac_addr, __args)
+	stmmac_do_void_callback(__priv, mac, get_umac_addr, __priv, __args)
 #define stmmac_set_eee_mode(__priv, __args...) \
 	stmmac_do_void_callback(__priv, mac, set_eee_mode, __args)
 #define stmmac_reset_eee_mode(__priv, __args...) \
@@ -560,8 +567,8 @@ struct stmmac_rx_queue;
 
 /* Helpers to manage the descriptors for chain and ring modes */
 struct stmmac_mode_ops {
-	void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
-		      unsigned int extend_desc);
+	void (*init) (struct stmmac_priv *priv, void *des, dma_addr_t phy_addr,
+		      unsigned int size, unsigned int extend_desc);
 	unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
 	int (*jumbo_frm)(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
 			 int csum);
@@ -572,7 +579,7 @@ struct stmmac_mode_ops {
 };
 
 #define stmmac_mode_init(__priv, __args...) \
-	stmmac_do_void_callback(__priv, mode, init, __args)
+	stmmac_do_void_callback(__priv, mode, init, __priv, __args)
 #define stmmac_is_jumbo_frm(__priv, __args...) \
 	stmmac_do_callback(__priv, mode, is_jumbo_frm, __args)
 #define stmmac_jumbo_frm(__priv, __args...) \
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 350e6670a576..22b8f27edfab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -61,7 +61,7 @@ static int ndesc_get_tx_status(struct net_device_stats *stats,
 	return ret;
 }
 
-static int ndesc_get_tx_len(struct dma_desc *p)
+static int ndesc_get_tx_len(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK);
 }
@@ -122,8 +122,8 @@ static int ndesc_get_rx_status(struct net_device_stats *stats,
 	return ret;
 }
 
-static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
-			       int end, int bfsize)
+static void ndesc_init_rx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+			       int disable_rx_ic, int mode, int end, int bfsize)
 {
 	int bfsize1;
 
@@ -181,9 +181,9 @@ static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 		ndesc_end_tx_desc_on_ring(p, ter);
 }
 
-static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-				  bool csum_flag, int mode, bool tx_own,
-				  bool ls, unsigned int tot_pkt_len)
+static void ndesc_prepare_tx_desc(struct stmmac_priv *priv, struct dma_desc *p,
+				  int is_fs, int len, bool csum_flag, int mode,
+				  bool tx_own, bool ls, unsigned int tot_pkt_len)
 {
 	unsigned int tdes1 = le32_to_cpu(p->des1);
 
@@ -292,12 +292,13 @@ static void ndesc_display_ring(void *head, unsigned int size, bool rx,
 	pr_info("\n");
 }
 
-static void ndesc_set_addr(struct dma_desc *p, dma_addr_t addr)
+static void ndesc_set_addr(struct stmmac_priv *priv, struct dma_desc *p,
+			   dma_addr_t addr)
 {
 	p->des2 = cpu_to_le32(addr);
 }
 
-static void ndesc_clear(struct dma_desc *p)
+static void ndesc_clear(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	p->des2 = 0;
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 4727f7be4f86..e8619853b6d6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2499,7 +2499,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
 				       true, priv->mode, true, true,
 				       xdp_desc.len);
 
-		stmmac_enable_dma_transmission(priv, priv->ioaddr);
+		stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 		tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
 		entry = tx_q->cur_tx;
@@ -4559,7 +4559,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len);
 
-	stmmac_enable_dma_transmission(priv, priv->ioaddr);
+	stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 	stmmac_flush_tx_descriptors(priv, queue);
 	stmmac_tx_timer_arm(priv, queue);
@@ -4775,7 +4775,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
 		priv->xstats.tx_set_ic_bit++;
 	}
 
-	stmmac_enable_dma_transmission(priv, priv->ioaddr);
+	stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
 
 	entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
 	tx_q->cur_tx = entry;
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 02/11] stmmac: dwmac1000: Add 64-bit DMA support
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms Feiyang Chen
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Add and extend the functions for Loongson platforms that support
64-bit DMA. Some Loongson platforms cannot write data to
DMA_RCV_BASE_ADDR64_HI, and we need to write to some shadow
addresses in dwmac1000_dma_init_rx().

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 .../net/ethernet/stmicro/stmmac/chain_mode.c  |  24 ++-
 drivers/net/ethernet/stmicro/stmmac/common.h  |   1 +
 drivers/net/ethernet/stmicro/stmmac/descs.h   |   7 +
 .../net/ethernet/stmicro/stmmac/descs_com.h   |  47 +++++-
 .../ethernet/stmicro/stmmac/dwmac1000_dma.c   |  46 +++--
 .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  17 ++
 .../net/ethernet/stmicro/stmmac/enh_desc.c    |  21 ++-
 drivers/net/ethernet/stmicro/stmmac/hwif.c    |   5 +-
 .../net/ethernet/stmicro/stmmac/ring_mode64.c | 158 ++++++++++++++++++
 include/linux/stmmac.h                        |   1 +
 11 files changed, 302 insertions(+), 27 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode64.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 7dd3d388068b..10f32ded2bd9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
 	      mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o	\
 	      dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
 	      stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
-	      stmmac_xdp.o \
+	      stmmac_xdp.o ring_mode64.o \
 	      $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index a95866871f3e..f363a2fb56f0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -36,6 +36,9 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
 	des2 = dma_map_single(priv->device, skb->data,
 			      bmax, DMA_TO_DEVICE);
 	desc->des2 = cpu_to_le32(des2);
+	if (priv->plat->dma_cfg->dma64)
+		desc->des3 = cpu_to_le32(upper_32_bits(des2));
+
 	if (dma_mapping_error(priv->device, des2))
 		return -1;
 	tx_q->tx_skbuff_dma[entry].buf = des2;
@@ -54,12 +57,16 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
 					      (skb->data + bmax * i),
 					      bmax, DMA_TO_DEVICE);
 			desc->des2 = cpu_to_le32(des2);
+			if (priv->plat->dma_cfg->dma64)
+				desc->des3 = cpu_to_le32(upper_32_bits(des2));
 			if (dma_mapping_error(priv->device, des2))
 				return -1;
 			tx_q->tx_skbuff_dma[entry].buf = des2;
 			tx_q->tx_skbuff_dma[entry].len = bmax;
 			stmmac_prepare_tx_desc(priv, desc, 0, bmax, csum,
-					STMMAC_CHAIN_MODE, 1, false, skb->len);
+					       STMMAC_CHAIN_MODE,
+					       !priv->plat->dma_cfg->dma64,
+					       false, skb->len);
 			len -= bmax;
 			i++;
 		} else {
@@ -67,6 +74,8 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
 					      (skb->data + bmax * i), len,
 					      DMA_TO_DEVICE);
 			desc->des2 = cpu_to_le32(des2);
+			if (priv->plat->dma_cfg->dma64)
+				desc->des3 = cpu_to_le32(upper_32_bits(des2));
 			if (dma_mapping_error(priv->device, des2))
 				return -1;
 			tx_q->tx_skbuff_dma[entry].buf = des2;
@@ -110,7 +119,12 @@ static void init_dma_chain(struct stmmac_priv *priv, void *des,
 		struct dma_extended_desc *p = (struct dma_extended_desc *)des;
 		for (i = 0; i < (size - 1); i++) {
 			dma_phy += sizeof(struct dma_extended_desc);
-			p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
+			if (priv->plat->dma_cfg->dma64) {
+				p->des6 = cpu_to_le32((unsigned int)dma_phy);
+				p->des7 = cpu_to_le32(upper_32_bits(dma_phy));
+			} else {
+				p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
+			}
 			p++;
 		}
 		p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);
@@ -130,6 +144,9 @@ static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
 {
 	struct stmmac_priv *priv = rx_q->priv_data;
 
+	if (priv->plat->dma_cfg->dma64)
+		return;
+
 	if (priv->hwts_rx_en && !priv->extend_desc)
 		/* NOTE: Device will overwrite des3 with timestamp value if
 		 * 1588-2002 time stamping is enabled, hence reinitialize it
@@ -146,6 +163,9 @@ static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
 	struct stmmac_priv *priv = tx_q->priv_data;
 	unsigned int entry = tx_q->dirty_tx;
 
+	if (priv->plat->dma_cfg->dma64)
+		return;
+
 	if (tx_q->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
 	    priv->hwts_tx_en)
 		/* NOTE: Device will overwrite des3 with timestamp value if
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 16e67c18b6f7..90a7784f71cb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -563,6 +563,7 @@ void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable);
 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
 
 extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops ring_mode64_ops;
 extern const struct stmmac_mode_ops chain_mode_ops;
 extern const struct stmmac_desc_ops dwmac4_desc_ops;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 49d6a866244f..223b77f0271c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -56,6 +56,9 @@
 #define ERDES1_BUFFER2_SIZE_SHIFT	16
 #define	ERDES1_DISABLE_IC		BIT(31)
 
+#define	E64RDES1_BUFFER1_SIZE_MASK	GENMASK(13, 0)
+#define	E64RDES1_BUFFER2_SIZE_MASK	GENMASK(29, 16)
+
 /* Normal transmit descriptor defines */
 /* TDES0 */
 #define	TDES0_DEFERRED			BIT(0)
@@ -122,6 +125,10 @@
 #define	ETDES1_BUFFER2_SIZE_MASK	GENMASK(28, 16)
 #define	ETDES1_BUFFER2_SIZE_SHIFT	16
 
+#define	E64TDES1_BUFFER1_SIZE_MASK	GENMASK(13, 0)
+#define	E64TDES1_BUFFER2_SIZE_MASK	GENMASK(28, 15)
+#define	E64TDES1_BUFFER2_SIZE_SHIFT	15
+
 /* Extended Receive descriptor definitions */
 #define	ERDES4_IP_PAYLOAD_TYPE_MASK	GENMASK(6, 2)
 #define	ERDES4_IP_HDR_ERR		BIT(3)
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index 40f7f2da9c5e..24f27088f7c8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -20,12 +20,18 @@
 
 /* Enhanced descriptors */
 static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end,
-					   int bfsize)
+					   int bfsize, bool dma64)
 {
-	if (bfsize == BUF_SIZE_16KiB)
-		p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
-				<< ERDES1_BUFFER2_SIZE_SHIFT)
-			   & ERDES1_BUFFER2_SIZE_MASK);
+	if (bfsize == BUF_SIZE_16KiB) {
+		if (dma64)
+			p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
+					<< ERDES1_BUFFER2_SIZE_SHIFT)
+				   & E64RDES1_BUFFER2_SIZE_MASK);
+		else
+			p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
+					<< ERDES1_BUFFER2_SIZE_SHIFT)
+				   & ERDES1_BUFFER2_SIZE_MASK);
+	}
 
 	if (end)
 		p->des1 |= cpu_to_le32(ERDES1_END_RING);
@@ -39,7 +45,7 @@ static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
 		p->des0 &= cpu_to_le32(~ETDES0_END_RING);
 }
 
-static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
+static inline void enh_set_tx_desc32_len_on_ring(struct dma_desc *p, int len)
 {
 	if (unlikely(len > BUF_SIZE_4KiB)) {
 		p->des1 |= cpu_to_le32((((len - BUF_SIZE_4KiB)
@@ -50,6 +56,27 @@ static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
 		p->des1 |= cpu_to_le32((len & ETDES1_BUFFER1_SIZE_MASK));
 }
 
+static inline void enh_set_tx_desc64_len_on_ring(struct dma_desc *p, int len)
+{
+	if (unlikely(len > BUF_SIZE_4KiB)) {
+		p->des1 |= cpu_to_le32((((len - BUF_SIZE_8KiB)
+					<< E64TDES1_BUFFER2_SIZE_SHIFT)
+			    & E64TDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_8KiB
+			    & E64TDES1_BUFFER1_SIZE_MASK));
+	} else {
+		p->des1 |= cpu_to_le32((len & E64TDES1_BUFFER1_SIZE_MASK));
+	}
+}
+
+static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len,
+					       bool dma64)
+{
+	if (dma64)
+		enh_set_tx_desc64_len_on_ring(p, len);
+	else
+		enh_set_tx_desc32_len_on_ring(p, len);
+}
+
 /* Normal descriptors */
 static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
 {
@@ -98,9 +125,13 @@ static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
 	p->des0 |= cpu_to_le32(ETDES0_SECOND_ADDRESS_CHAINED);
 }
 
-static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
+static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len,
+						bool dma64)
 {
-	p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
+	if (dma64)
+		p->des1 |= cpu_to_le32(len & E64TDES1_BUFFER1_SIZE_MASK);
+	else
+		p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
 }
 
 /* Normal descriptors */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index ce0e6ca6f3a2..1cc79011176b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -15,6 +15,7 @@
 #include <asm/io.h>
 #include "dwmac1000.h"
 #include "dwmac_dma.h"
+#include "stmmac.h"
 
 static void dwmac1000_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
 			      struct stmmac_axi *axi)
@@ -30,13 +31,23 @@ static void dwmac1000_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
 	if (axi->axi_xit_frm)
 		value |= DMA_AXI_LPI_XIT_FRM;
 
-	value &= ~DMA_AXI_WR_OSR_LMT;
-	value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
-		 DMA_AXI_WR_OSR_LMT_SHIFT;
+	if (priv->plat->dma_cfg->dma64) {
+		value &= ~DMA_AXI_WR_OSR64_LMT;
+		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR64_LMT_MASK) <<
+			 DMA_AXI_WR_OSR64_LMT_SHIFT;
 
-	value &= ~DMA_AXI_RD_OSR_LMT;
-	value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
-		 DMA_AXI_RD_OSR_LMT_SHIFT;
+		value &= ~DMA_AXI_RD_OSR64_LMT;
+		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR64_LMT_MASK) <<
+			 DMA_AXI_RD_OSR64_LMT_SHIFT;
+	} else {
+		value &= ~DMA_AXI_WR_OSR_LMT;
+		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
+			 DMA_AXI_WR_OSR_LMT_SHIFT;
+
+		value &= ~DMA_AXI_RD_OSR_LMT;
+		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
+			 DMA_AXI_RD_OSR_LMT_SHIFT;
+	}
 
 	/* Depending on the UNDEF bit the Master AXI will perform any burst
 	 * length according to the BLEN programmed (by default all BLEN are
@@ -109,6 +120,9 @@ static void dwmac1000_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
 
 	/* Mask interrupts by writing to CSR7 */
 	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+
+	if (dma_cfg->dma64)
+		writel(0x100, ioaddr + DMA_NEWFUNC_CONFIG);
 }
 
 static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
@@ -116,8 +130,15 @@ static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
 				  struct stmmac_dma_cfg *dma_cfg,
 				  dma_addr_t dma_rx_phy, u32 chan)
 {
-	/* RX descriptor base address list must be written into DMA CSR3 */
-	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
+	if (dma_cfg->dma64) {
+		writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR64);
+		writel(upper_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR64_HI);
+		writel(upper_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR64_HI_SHADOW1);
+		writel(upper_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR64_HI_SHADOW2);
+	} else {
+		/* RX descriptor base address list must be written into DMA CSR3 */
+		writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
+	}
 }
 
 static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
@@ -125,8 +146,13 @@ static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
 				  struct stmmac_dma_cfg *dma_cfg,
 				  dma_addr_t dma_tx_phy, u32 chan)
 {
-	/* TX descriptor base address list must be written into DMA CSR4 */
-	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
+	if (dma_cfg->dma64) {
+		writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR64);
+		writel(upper_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR64_HI);
+	} else {
+		/* TX descriptor base address list must be written into DMA CSR4 */
+		writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
+	}
 }
 
 static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 77141391bd2f..bcb3b572f2f2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -16,11 +16,18 @@
 #define DMA_XMT_POLL_DEMAND	0x00001004	/* Transmit Poll Demand */
 #define DMA_RCV_POLL_DEMAND	0x00001008	/* Received Poll Demand */
 #define DMA_RCV_BASE_ADDR	0x0000100c	/* Receive List Base */
+#define DMA_RCV_BASE_ADDR64	0x00001090
+#define DMA_RCV_BASE_ADDR64_HI	0x00001094
+#define DMA_RCV_BASE_ADDR64_HI_SHADOW1	0x00001068
+#define DMA_RCV_BASE_ADDR64_HI_SHADOW2	0x000010a8
 #define DMA_TX_BASE_ADDR	0x00001010	/* Transmit List Base */
+#define DMA_TX_BASE_ADDR64	0x00001098
+#define DMA_TX_BASE_ADDR64_HI	0x0000109c
 #define DMA_STATUS		0x00001014	/* Status Register */
 #define DMA_CONTROL		0x00001018	/* Ctrl (Operational Mode) */
 #define DMA_INTR_ENA		0x0000101c	/* Interrupt Enable */
 #define DMA_MISSED_FRAME_CTR	0x00001020	/* Missed Frame Counter */
+#define DMA_NEWFUNC_CONFIG	0x00001080	/* New Function Config */
 
 /* SW Reset */
 #define DMA_BUS_MODE_SFT_RESET	0x00000001	/* Software Reset */
@@ -39,10 +46,20 @@
 #define DMA_AXI_RD_OSR_LMT	GENMASK(19, 16)
 #define DMA_AXI_RD_OSR_LMT_SHIFT	16
 #define DMA_AXI_RD_OSR_LMT_MASK	0xf
+#define DMA_AXI_WR_OSR64_LMT	GENMASK(21, 20)
+#define DMA_AXI_WR_OSR64_LMT_SHIFT	20
+#define DMA_AXI_WR_OSR64_LMT_MASK	0x3
+#define DMA_AXI_RD_OSR64_LMT	GENMASK(17, 16)
+#define DMA_AXI_RD_OSR64_LMT_SHIFT	16
+#define DMA_AXI_RD_OSR64_LMT_MASK	0x3
 
 #define DMA_AXI_OSR_MAX		0xf
 #define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
 			       (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
+#define DMA_AXI_OSR64_MAX	0x3
+#define DMA_AXI_MAX_OSR64_LIMIT	((DMA_AXI_OSR64_MAX << DMA_AXI_WR_OSR64_LMT_SHIFT) | \
+				 (DMA_AXI_OSR64_MAX << DMA_AXI_RD_OSR64_LMT_SHIFT))
+
 #define	DMA_AXI_1KBBE		BIT(13)
 #define DMA_AXI_AAL		BIT(12)
 #define DMA_AXI_BLEN256		BIT(7)
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 1932a3a8e03c..ee07006c97c1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -11,6 +11,7 @@
 #include <linux/stmmac.h>
 #include "common.h"
 #include "descs_com.h"
+#include "stmmac.h"
 
 static int enh_desc_get_tx_status(struct net_device_stats *stats,
 				  struct stmmac_extra_stats *x,
@@ -81,7 +82,10 @@ static int enh_desc_get_tx_status(struct net_device_stats *stats,
 
 static int enh_desc_get_tx_len(struct stmmac_priv *priv, struct dma_desc *p)
 {
-	return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
+	if (priv->plat->dma_cfg->dma64)
+		return (le32_to_cpu(p->des1) & E64TDES1_BUFFER1_SIZE_MASK);
+	else
+		return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
 }
 
 static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
@@ -263,12 +267,15 @@ static void enh_desc_init_rx_desc(struct stmmac_priv *priv, struct dma_desc *p,
 	p->des0 |= cpu_to_le32(RDES0_OWN);
 
 	bfsize1 = min(bfsize, BUF_SIZE_8KiB);
-	p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
+	if (priv->plat->dma_cfg->dma64)
+		p->des1 |= cpu_to_le32(bfsize1 & E64RDES1_BUFFER1_SIZE_MASK);
+	else
+		p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
 
 	if (mode == STMMAC_CHAIN_MODE)
 		ehn_desc_rx_set_on_chain(p);
 	else
-		ehn_desc_rx_set_on_ring(p, end, bfsize);
+		ehn_desc_rx_set_on_ring(p, end, bfsize, priv->plat->dma_cfg->dma64);
 
 	if (disable_rx_ic)
 		p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
@@ -321,9 +328,9 @@ static void enh_desc_prepare_tx_desc(struct stmmac_priv *priv, struct dma_desc *
 	unsigned int tdes0 = le32_to_cpu(p->des0);
 
 	if (mode == STMMAC_CHAIN_MODE)
-		enh_set_tx_desc_len_on_chain(p, len);
+		enh_set_tx_desc_len_on_chain(p, len, priv->plat->dma_cfg->dma64);
 	else
-		enh_set_tx_desc_len_on_ring(p, len);
+		enh_set_tx_desc_len_on_ring(p, len, priv->plat->dma_cfg->dma64);
 
 	if (is_fs)
 		tdes0 |= ETDES0_FIRST_SEGMENT;
@@ -445,11 +452,15 @@ static void enh_desc_set_addr(struct stmmac_priv *priv, struct dma_desc *p,
 			      dma_addr_t addr)
 {
 	p->des2 = cpu_to_le32(addr);
+	if (priv->plat->dma_cfg->dma64)
+		p->des3 = cpu_to_le32(upper_32_bits(addr));
 }
 
 static void enh_desc_clear(struct stmmac_priv *priv, struct dma_desc *p)
 {
 	p->des2 = 0;
+	if (priv->plat->dma_cfg->dma64)
+		p->des3 = 0;
 }
 
 const struct stmmac_desc_ops enh_desc_ops = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 93cead5613e3..c5768bbec38e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -46,7 +46,10 @@ static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
 	} else {
 		dev_info(priv->device, "Ring mode enabled\n");
 		priv->mode = STMMAC_RING_MODE;
-		mac->mode = &ring_mode_ops;
+		if (priv->plat->dma_cfg->dma64)
+			mac->mode = &ring_mode64_ops;
+		else
+			mac->mode = &ring_mode_ops;
 	}
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode64.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode64.c
new file mode 100644
index 000000000000..e525201221d9
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode64.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Specialised functions for managing Ring mode
+ * It defines all the functions used to handle the normal/enhanced
+ * descriptors in case of the DMA is configured to work in chained or
+ * in ring mode.
+ *
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ *
+ * Based on code taken from ring_mode.c which is:
+ * Copyright(C) 2011  STMicroelectronics Ltd
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ */
+
+#include "stmmac.h"
+
+static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
+		     int csum)
+{
+	unsigned int nopaged_len = skb_headlen(skb);
+	struct stmmac_priv *priv = tx_q->priv_data;
+	unsigned int entry = tx_q->cur_tx;
+	struct dma_extended_desc *edesc;
+	unsigned int bmax, len, des2;
+	struct dma_desc *desc;
+
+	if (priv->extend_desc) {
+		edesc = tx_q->dma_etx + entry;
+		desc = (struct dma_desc *)edesc;
+	} else {
+		desc = tx_q->dma_tx + entry;
+	}
+
+	bmax = BUF_SIZE_8KiB;
+
+	len = nopaged_len - bmax * 2;
+
+	if (nopaged_len > bmax * 2) {
+		des2 = dma_map_single(priv->device, skb->data, bmax * 2,
+				      DMA_TO_DEVICE);
+		desc->des2 = cpu_to_le32(des2);
+		desc->des3 = cpu_to_le32(upper_32_bits(des2));
+		if (dma_mapping_error(priv->device, des2))
+			return -1;
+
+		tx_q->tx_skbuff_dma[entry].buf = des2;
+		tx_q->tx_skbuff_dma[entry].len = bmax * 2;
+		tx_q->tx_skbuff_dma[entry].is_jumbo = true;
+
+		edesc->des6 = cpu_to_le32(des2 + bmax);
+		edesc->des7 = cpu_to_le32(upper_32_bits(des2 + bmax));
+		stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum,
+				       STMMAC_RING_MODE, 1, false, skb->len);
+
+		tx_q->tx_skbuff[entry] = NULL;
+		entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+		edesc = tx_q->dma_etx + entry;
+		desc = &edesc->basic;
+
+		des2 = dma_map_single(priv->device, skb->data + bmax, len,
+				      DMA_TO_DEVICE);
+		desc->des2 = cpu_to_le32(des2);
+		desc->des3 = cpu_to_le32(upper_32_bits(des2));
+		if (dma_mapping_error(priv->device, des2))
+			return -1;
+		tx_q->tx_skbuff_dma[entry].buf = des2;
+		tx_q->tx_skbuff_dma[entry].len = len;
+		tx_q->tx_skbuff_dma[entry].is_jumbo = true;
+
+		edesc->des6 = cpu_to_le32(des2 + bmax);
+		edesc->des7 = cpu_to_le32(upper_32_bits(des2 + bmax));
+		stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
+				       STMMAC_RING_MODE, 1, !skb_is_nonlinear(skb),
+				       skb->len);
+	} else {
+		des2 = dma_map_single(priv->device, skb->data,
+				      nopaged_len, DMA_TO_DEVICE);
+		desc->des2 = cpu_to_le32(des2);
+		desc->des3 = cpu_to_le32(upper_32_bits(des2));
+		if (dma_mapping_error(priv->device, des2))
+			return -1;
+		tx_q->tx_skbuff_dma[entry].buf = des2;
+		tx_q->tx_skbuff_dma[entry].len = nopaged_len;
+		tx_q->tx_skbuff_dma[entry].is_jumbo = true;
+		edesc->des6 = cpu_to_le32(des2 + bmax);
+		edesc->des7 = cpu_to_le32(upper_32_bits(des2 + bmax));
+		stmmac_prepare_tx_desc(priv, desc, 1, nopaged_len, csum,
+				       STMMAC_RING_MODE, 1, !skb_is_nonlinear(skb),
+				       skb->len);
+	}
+
+	tx_q->cur_tx = entry;
+
+	return entry;
+}
+
+static unsigned int is_jumbo_frm(int len, int enh_desc)
+{
+	unsigned int ret = 0;
+
+	if (len >= BUF_SIZE_4KiB)
+		ret = 1;
+
+	return ret;
+}
+
+static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
+{
+	struct dma_extended_desc *edesc = (struct dma_extended_desc *)p;
+	struct stmmac_priv *priv = rx_q->priv_data;
+
+	/* Fill DES3 in case of RING mode */
+	if (priv->dma_conf.dma_buf_sz >= BUF_SIZE_8KiB) {
+		edesc->des6 = cpu_to_le32(le32_to_cpu(edesc->basic.des2) +
+					  BUF_SIZE_8KiB);
+		edesc->des7 = cpu_to_le32(le32_to_cpu(edesc->basic.des3));
+	}
+}
+
+/* In ring mode we need to fill the desc3 because it is used as buffer */
+static void init_desc3(struct dma_desc *p)
+{
+	struct dma_extended_desc *edesc = (struct dma_extended_desc *)p;
+
+	edesc->des6 = cpu_to_le32(le32_to_cpu(edesc->basic.des2) +
+				  BUF_SIZE_8KiB);
+	edesc->des7 = cpu_to_le32(le32_to_cpu(edesc->basic.des3));
+}
+
+static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
+{
+	struct dma_extended_desc *edesc = (struct dma_extended_desc *)p;
+	unsigned int entry = tx_q->dirty_tx;
+
+	if (unlikely(tx_q->tx_skbuff_dma[entry].is_jumbo)) {
+		edesc->des6 = 0;
+		edesc->des7 = 0;
+	}
+}
+
+static int set_16kib_bfsize(int mtu)
+{
+	int ret = 0;
+
+	if (unlikely(mtu >= BUF_SIZE_8KiB))
+		ret = BUF_SIZE_16KiB;
+
+	return ret;
+}
+
+const struct stmmac_mode_ops ring_mode64_ops = {
+	.is_jumbo_frm = is_jumbo_frm,
+	.jumbo_frm = jumbo_frm,
+	.refill_desc3 = refill_desc3,
+	.init_desc3 = init_desc3,
+	.clean_desc3 = clean_desc3,
+	.set_16kib_bfsize = set_16kib_bfsize,
+};
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 06090538fe2d..2fcd83f6db14 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -98,6 +98,7 @@ struct stmmac_dma_cfg {
 	bool eame;
 	bool multi_msi_en;
 	bool dche;
+	bool dma64;
 };
 
 #define AXI_BLEN	7
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 02/11] stmmac: dwmac1000: Add 64-bit DMA support Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22 16:13   ` Serge Semin
  2023-08-22  9:40 ` [PATCH v4 04/11] net: stmmac: Allow platforms to set irq_flags Feiyang Chen
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Loongson platforms use an extended GMAC which supports 64-bit DMA
and multi-channel.

There are two kinds of Loongson platforms. The first kind shares
the same registers and has similar logic with dwmac1000. The second
kind uses different registers and has more features.

Add extended GMAC support and then add two HWIF entries for Loongson
platforms.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
 drivers/net/ethernet/stmicro/stmmac/common.h  |   2 +
 drivers/net/ethernet/stmicro/stmmac/dwegmac.h | 332 +++++++++++
 .../ethernet/stmicro/stmmac/dwegmac_core.c    | 552 ++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/dwegmac_dma.c | 516 ++++++++++++++++
 .../net/ethernet/stmicro/stmmac/dwegmac_dma.h | 190 ++++++
 drivers/net/ethernet/stmicro/stmmac/hwif.c    |  54 +-
 drivers/net/ethernet/stmicro/stmmac/hwif.h    |   2 +
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |   2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |   3 +-
 include/linux/stmmac.h                        |   1 +
 11 files changed, 1651 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac.h
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 10f32ded2bd9..1238cd736910 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
 	      mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o	\
 	      dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
 	      stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
-	      stmmac_xdp.o ring_mode64.o \
+	      stmmac_xdp.o ring_mode64.o dwegmac_core.o dwegmac_dma.o \
 	      $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 90a7784f71cb..74528a16b93a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -36,6 +36,7 @@
 #define DWMAC_CORE_5_20		0x52
 #define DWXGMAC_CORE_2_10	0x21
 #define DWXLGMAC_CORE_2_00	0x20
+#define DWEGMAC_CORE_1_00	0x10
 
 /* Device ID */
 #define DWXGMAC_ID		0x76
@@ -547,6 +548,7 @@ int dwmac1000_setup(struct stmmac_priv *priv);
 int dwmac4_setup(struct stmmac_priv *priv);
 int dwxgmac2_setup(struct stmmac_priv *priv);
 int dwxlgmac2_setup(struct stmmac_priv *priv);
+int dwegmac_setup(struct stmmac_priv *priv);
 
 void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
 			 unsigned int high, unsigned int low);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac.h b/drivers/net/ethernet/stmicro/stmmac/dwegmac.h
new file mode 100644
index 000000000000..6f8fcf3ed409
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac.h
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __DWEGMAC_H__
+#define __DWEGMAC_H__
+
+#include <linux/phy.h>
+#include "common.h"
+
+#define GMAC_CONTROL			0x00000000	/* Configuration */
+#define GMAC_FRAME_FILTER		0x00000004	/* Frame Filter */
+#define GMAC_HASH_HIGH			0x00000008	/* Multicast Hash Table High */
+#define GMAC_HASH_LOW			0x0000000c	/* Multicast Hash Table Low */
+#define GMAC_MII_ADDR			0x00000010	/* MII Address */
+#define GMAC_MII_DATA			0x00000014	/* MII Data */
+#define GMAC_FLOW_CTRL			0x00000018	/* Flow Control */
+#define GMAC_VLAN_TAG			0x0000001c	/* VLAN Tag */
+#define GMAC_DEBUG			0x00000024	/* GMAC debug register */
+#define GMAC_WAKEUP_FILTER		0x00000028	/* Wake-up Frame Filter */
+
+#define GMAC_INT_STATUS			0x00000038	/* interrupt status register */
+#define GMAC_INT_STATUS_PMT		BIT(3)
+#define GMAC_INT_STATUS_MMCIS		BIT(4)
+#define GMAC_INT_STATUS_MMCRIS		BIT(5)
+#define GMAC_INT_STATUS_MMCTIS		BIT(6)
+#define GMAC_INT_STATUS_MMCCSUM		BIT(7)
+#define GMAC_INT_STATUS_TSTAMP		BIT(9)
+#define GMAC_INT_STATUS_LPIIS		BIT(10)
+
+/* interrupt mask register */
+#define	GMAC_INT_MASK			0x0000003c
+#define	GMAC_INT_DISABLE_RGMII		BIT(0)
+#define	GMAC_INT_DISABLE_PCSLINK	BIT(1)
+#define	GMAC_INT_DISABLE_PCSAN		BIT(2)
+#define	GMAC_INT_DISABLE_PMT		BIT(3)
+#define	GMAC_INT_DISABLE_TIMESTAMP	BIT(9)
+#define	GMAC_INT_DISABLE_PCS		(GMAC_INT_DISABLE_RGMII | \
+					 GMAC_INT_DISABLE_PCSLINK | \
+					 GMAC_INT_DISABLE_PCSAN)
+#define	GMAC_INT_DEFAULT_MASK		(GMAC_INT_DISABLE_TIMESTAMP | \
+					 GMAC_INT_DISABLE_PCS)
+
+/* PMT Control and Status */
+#define GMAC_PMT			0x0000002c
+enum power_event {
+	pointer_reset = 0x80000000,
+	global_unicast = 0x00000200,
+	wake_up_rx_frame = 0x00000040,
+	magic_frame = 0x00000020,
+	wake_up_frame_en = 0x00000004,
+	magic_pkt_en = 0x00000002,
+	power_down = 0x00000001,
+};
+
+/* Energy Efficient Ethernet (EEE)
+ *
+ * LPI status, timer and control register offset
+ */
+#define LPI_CTRL_STATUS			0x0030
+#define LPI_TIMER_CTRL			0x0034
+
+/* LPI control and status defines */
+#define LPI_CTRL_STATUS_LPITXA		0x00080000	/* Enable LPI TX Automate */
+#define LPI_CTRL_STATUS_PLSEN		0x00040000	/* Enable PHY Link Status */
+#define LPI_CTRL_STATUS_PLS		0x00020000	/* PHY Link Status */
+#define LPI_CTRL_STATUS_LPIEN		0x00010000	/* LPI Enable */
+#define LPI_CTRL_STATUS_RLPIST		0x00000200	/* Receive LPI state */
+#define LPI_CTRL_STATUS_TLPIST		0x00000100	/* Transmit LPI state */
+#define LPI_CTRL_STATUS_RLPIEX		0x00000008	/* Receive LPI Exit */
+#define LPI_CTRL_STATUS_RLPIEN		0x00000004	/* Receive LPI Entry */
+#define LPI_CTRL_STATUS_TLPIEX		0x00000002	/* Transmit LPI Exit */
+#define LPI_CTRL_STATUS_TLPIEN		0x00000001	/* Transmit LPI Entry */
+
+/* GMAC HW ADDR regs */
+#define GMAC_ADDR_HIGH(reg)		((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
+					 0x00000040 + (reg * 8))
+#define GMAC_ADDR_LOW(reg)		((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
+					 0x00000044 + (reg * 8))
+#define GMAC_MAX_PERFECT_ADDRESSES	1
+
+#define GMAC_PCS_BASE			0x000000c0	/* PCS register base */
+#define GMAC_RGSMIIIS			0x000000d8	/* RGMII/SMII status */
+
+/* SGMII/RGMII status register */
+#define GMAC_RGSMIIIS_LNKMODE		BIT(0)
+#define GMAC_RGSMIIIS_SPEED		GENMASK(2, 1)
+#define GMAC_RGSMIIIS_SPEED_SHIFT	1
+#define GMAC_RGSMIIIS_LNKSTS		BIT(3)
+#define GMAC_RGSMIIIS_JABTO		BIT(4)
+#define GMAC_RGSMIIIS_FALSECARDET	BIT(5)
+#define GMAC_RGSMIIIS_SMIDRXS		BIT(16)
+/* LNKMOD */
+#define GMAC_RGSMIIIS_LNKMOD_MASK	0x1
+/* LNKSPEED */
+#define GMAC_RGSMIIIS_SPEED_125		0x2
+#define GMAC_RGSMIIIS_SPEED_25		0x1
+#define GMAC_RGSMIIIS_SPEED_2_5		0x0
+
+/* GMAC Configuration defines */
+#define GMAC_CONTROL_2K			0x08000000	/* IEEE 802.3as 2K packets */
+#define GMAC_CONTROL_TC			0x01000000	/* Transmit Conf. in RGMII/SGMII */
+#define GMAC_CONTROL_WD			0x00800000	/* Disable Watchdog on receive */
+#define GMAC_CONTROL_JD			0x00400000	/* Jabber disable */
+#define GMAC_CONTROL_BE			0x00200000	/* Frame Burst Enable */
+#define GMAC_CONTROL_JE			0x00100000	/* Jumbo frame */
+enum inter_frame_gap {
+	GMAC_CONTROL_IFG_88 = 0x00040000,
+	GMAC_CONTROL_IFG_80 = 0x00020000,
+	GMAC_CONTROL_IFG_40 = 0x000e0000,
+};
+#define GMAC_CONTROL_DCRS		0x00010000	/* Disable carrier sense */
+#define GMAC_CONTROL_PS			0x00008000	/* Port Select 0:GMI 1:MII */
+#define GMAC_CONTROL_FES		0x00004000	/* Speed 0:10 1:100 */
+#define GMAC_CONTROL_DO			0x00002000	/* Disable Rx Own */
+#define GMAC_CONTROL_LM			0x00001000	/* Loop-back mode */
+#define GMAC_CONTROL_DM			0x00000800	/* Duplex Mode */
+#define GMAC_CONTROL_IPC		0x00000400	/* Checksum Offload */
+#define GMAC_CONTROL_DR			0x00000200	/* Disable Retry */
+#define GMAC_CONTROL_LUD		0x00000100	/* Link up/down */
+#define GMAC_CONTROL_ACS		0x00000080	/* Auto Pad/FCS Stripping */
+#define GMAC_CONTROL_DC			0x00000010	/* Deferral Check */
+#define GMAC_CONTROL_TE			0x00000008	/* Transmitter Enable */
+#define GMAC_CONTROL_RE			0x00000004	/* Receiver Enable */
+
+#define GMAC_CORE_INIT			(GMAC_CONTROL_JD | GMAC_CONTROL_PS | \
+					 GMAC_CONTROL_BE | GMAC_CONTROL_DCRS | \
+					 GMAC_CONTROL_ACS)
+
+/* GMAC Frame Filter defines */
+#define GMAC_FRAME_FILTER_PR		0x00000001	/* Promiscuous Mode */
+#define GMAC_FRAME_FILTER_HUC		0x00000002	/* Hash Unicast */
+#define GMAC_FRAME_FILTER_HMC		0x00000004	/* Hash Multicast */
+#define GMAC_FRAME_FILTER_DAIF		0x00000008	/* DA Inverse Filtering */
+#define GMAC_FRAME_FILTER_PM		0x00000010	/* Pass all multicast */
+#define GMAC_FRAME_FILTER_DBF		0x00000020	/* Disable Broadcast frames */
+#define GMAC_FRAME_FILTER_PCF		0x00000080	/* Pass Control frames */
+#define GMAC_FRAME_FILTER_SAIF		0x00000100	/* Inverse Filtering */
+#define GMAC_FRAME_FILTER_SAF		0x00000200	/* Source Address Filter */
+#define GMAC_FRAME_FILTER_HPF		0x00000400	/* Hash or perfect Filter */
+#define GMAC_FRAME_FILTER_RA		0x80000000	/* Receive all mode */
+/* GMII ADDR  defines */
+#define GMAC_MII_ADDR_WRITE		0x00000002	/* MII Write */
+#define GMAC_MII_ADDR_BUSY		0x00000001	/* MII Busy */
+/* GMAC FLOW CTRL defines */
+#define GMAC_FLOW_CTRL_PT_MASK		0xffff0000	/* Pause Time Mask */
+#define GMAC_FLOW_CTRL_PT_SHIFT		16
+#define GMAC_FLOW_CTRL_UP		0x00000008	/* Unicast pause frame enable */
+#define GMAC_FLOW_CTRL_RFE		0x00000004	/* Rx Flow Control Enable */
+#define GMAC_FLOW_CTRL_TFE		0x00000002	/* Tx Flow Control Enable */
+#define GMAC_FLOW_CTRL_FCB_BPA		0x00000001	/* Flow Control Busy ... */
+
+/* DEBUG Register defines */
+/* MTL TxStatus FIFO */
+#define GMAC_DEBUG_TXSTSFSTS		BIT(25)	/* MTL TxStatus FIFO Full Status */
+#define GMAC_DEBUG_TXFSTS		BIT(24) /* MTL Tx FIFO Not Empty Status */
+#define GMAC_DEBUG_TWCSTS		BIT(22) /* MTL Tx FIFO Write Controller */
+/* MTL Tx FIFO Read Controller Status */
+#define GMAC_DEBUG_TRCSTS_MASK		GENMASK(21, 20)
+#define GMAC_DEBUG_TRCSTS_SHIFT		20
+#define GMAC_DEBUG_TRCSTS_IDLE		0
+#define GMAC_DEBUG_TRCSTS_READ		1
+#define GMAC_DEBUG_TRCSTS_TXW		2
+#define GMAC_DEBUG_TRCSTS_WRITE		3
+#define GMAC_DEBUG_TXPAUSED		BIT(19) /* MAC Transmitter in PAUSE */
+/* MAC Transmit Frame Controller Status */
+#define GMAC_DEBUG_TFCSTS_MASK		GENMASK(18, 17)
+#define GMAC_DEBUG_TFCSTS_SHIFT		17
+#define GMAC_DEBUG_TFCSTS_IDLE		0
+#define GMAC_DEBUG_TFCSTS_WAIT		1
+#define GMAC_DEBUG_TFCSTS_GEN_PAUSE	2
+#define GMAC_DEBUG_TFCSTS_XFER		3
+/* MAC GMII or MII Transmit Protocol Engine Status */
+#define GMAC_DEBUG_TPESTS		BIT(16)
+#define GMAC_DEBUG_RXFSTS_MASK		GENMASK(9, 8) /* MTL Rx FIFO Fill-level */
+#define GMAC_DEBUG_RXFSTS_SHIFT		8
+#define GMAC_DEBUG_RXFSTS_EMPTY		0
+#define GMAC_DEBUG_RXFSTS_BT		1
+#define GMAC_DEBUG_RXFSTS_AT		2
+#define GMAC_DEBUG_RXFSTS_FULL		3
+#define GMAC_DEBUG_RRCSTS_MASK		GENMASK(6, 5) /* MTL Rx FIFO Read Controller */
+#define GMAC_DEBUG_RRCSTS_SHIFT		5
+#define GMAC_DEBUG_RRCSTS_IDLE		0
+#define GMAC_DEBUG_RRCSTS_RDATA		1
+#define GMAC_DEBUG_RRCSTS_RSTAT		2
+#define GMAC_DEBUG_RRCSTS_FLUSH		3
+#define GMAC_DEBUG_RWCSTS		BIT(4) /* MTL Rx FIFO Write Controller Active */
+/* MAC Receive Frame Controller FIFO Status */
+#define GMAC_DEBUG_RFCFCSTS_MASK	GENMASK(2, 1)
+#define GMAC_DEBUG_RFCFCSTS_SHIFT	1
+/* MAC GMII or MII Receive Protocol Engine Status */
+#define GMAC_DEBUG_RPESTS		BIT(0)
+
+/*--- DMA BLOCK defines ---*/
+/* DMA Bus Mode register defines */
+#define DMA_BUS_MODE_DA			0x00000002	/* Arbitration scheme */
+#define DMA_BUS_MODE_DSL_MASK		0x0000007c	/* Descriptor Skip Length */
+#define DMA_BUS_MODE_DSL_SHIFT		2		/*   (in DWORDS)      */
+/* Programmable burst length (passed thorugh platform)*/
+#define DMA_BUS_MODE_PBL_MASK		0x00003f00	/* Programmable Burst Len */
+#define DMA_BUS_MODE_PBL_SHIFT		8
+#define DMA_BUS_MODE_ATDS		0x00000080	/* Alternate Descriptor Size */
+
+enum rx_tx_priority_ratio {
+	double_ratio = 0x00004000,	/* 2:1 */
+	triple_ratio = 0x00008000,	/* 3:1 */
+	quadruple_ratio = 0x0000c000,	/* 4:1 */
+};
+
+#define DMA_BUS_MODE_FB			0x00010000	/* Fixed burst */
+#define DMA_BUS_MODE_MB			0x04000000	/* Mixed burst */
+#define DMA_BUS_MODE_RPBL_MASK		0x007e0000	/* Rx-Programmable Burst Len */
+#define DMA_BUS_MODE_RPBL_SHIFT		17
+#define DMA_BUS_MODE_USP		0x00800000
+#define DMA_BUS_MODE_MAXPBL		0x01000000
+#define DMA_BUS_MODE_AAL		0x02000000
+
+/* DMA CRS Control and Status Register Mapping */
+#define DMA_HOST_TX_DESC		0x00001048	/* Current Host Tx descriptor */
+#define DMA_HOST_RX_DESC		0x0000104c	/* Current Host Rx descriptor */
+/*  DMA Bus Mode register defines */
+#define DMA_BUS_PR_RATIO_MASK		0x0000c000	/* Rx/Tx priority ratio */
+#define DMA_BUS_PR_RATIO_SHIFT		14
+#define DMA_BUS_FB			0x00010000	/* Fixed Burst */
+
+/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
+/* Disable Drop TCP/IP csum error */
+#define DMA_CONTROL_DT			0x04000000
+#define DMA_CONTROL_RSF			0x02000000	/* Receive Store and Forward */
+#define DMA_CONTROL_DFF			0x01000000	/* Disaable flushing */
+/* Threshold for Activating the FC */
+enum rfa {
+	act_full_minus_1 = 0x00800000,
+	act_full_minus_2 = 0x00800200,
+	act_full_minus_3 = 0x00800400,
+	act_full_minus_4 = 0x00800600,
+};
+/* Threshold for Deactivating the FC */
+enum rfd {
+	deac_full_minus_1 = 0x00400000,
+	deac_full_minus_2 = 0x00400800,
+	deac_full_minus_3 = 0x00401000,
+	deac_full_minus_4 = 0x00401800,
+};
+#define DMA_CONTROL_TSF	0x00200000	/* Transmit  Store and Forward */
+
+enum ttc_control {
+	DMA_CONTROL_TTC_64 = 0x00000000,
+	DMA_CONTROL_TTC_128 = 0x00004000,
+	DMA_CONTROL_TTC_192 = 0x00008000,
+	DMA_CONTROL_TTC_256 = 0x0000c000,
+	DMA_CONTROL_TTC_40 = 0x00010000,
+	DMA_CONTROL_TTC_32 = 0x00014000,
+	DMA_CONTROL_TTC_24 = 0x00018000,
+	DMA_CONTROL_TTC_16 = 0x0001c000,
+};
+#define DMA_CONTROL_TC_TX_MASK		0xfffe3fff
+
+#define DMA_CONTROL_EFC			0x00000100
+#define DMA_CONTROL_FEF			0x00000080
+#define DMA_CONTROL_FUF			0x00000040
+
+/* Receive flow control activation field
+ * RFA field in DMA control register, bits 23,10:9
+ */
+#define DMA_CONTROL_RFA_MASK		0x00800600
+
+/* Receive flow control deactivation field
+ * RFD field in DMA control register, bits 22,12:11
+ */
+#define DMA_CONTROL_RFD_MASK		0x00401800
+
+/* RFD and RFA fields are encoded as follows
+ *
+ *   Bit Field
+ *   0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled)
+ *   0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled)
+ *   0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled)
+ *   0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled)
+ *   1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled)
+ *   1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled)
+ *   1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled)
+ *   1,11 - Reserved
+ *
+ * RFD should always be > RFA for a given FIFO size. RFD == RFA may work,
+ * but packet throughput performance may not be as expected.
+ *
+ * Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame
+ * detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause
+ * Description).
+ *
+ * Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6),
+ * is set to 0. This allows pause frames with a quanta of 0 to be sent
+ * as an XOFF message to the link peer.
+ */
+
+#define RFA_FULL_MINUS_1K		0x00000000
+#define RFA_FULL_MINUS_2K		0x00000200
+#define RFA_FULL_MINUS_3K		0x00000400
+#define RFA_FULL_MINUS_4K		0x00000600
+#define RFA_FULL_MINUS_5K		0x00800000
+#define RFA_FULL_MINUS_6K		0x00800200
+#define RFA_FULL_MINUS_7K		0x00800400
+
+#define RFD_FULL_MINUS_1K		0x00000000
+#define RFD_FULL_MINUS_2K		0x00000800
+#define RFD_FULL_MINUS_3K		0x00001000
+#define RFD_FULL_MINUS_4K		0x00001800
+#define RFD_FULL_MINUS_5K		0x00400000
+#define RFD_FULL_MINUS_6K		0x00400800
+#define RFD_FULL_MINUS_7K		0x00401000
+
+enum rtc_control {
+	DMA_CONTROL_RTC_64 = 0x00000000,
+	DMA_CONTROL_RTC_32 = 0x00000008,
+	DMA_CONTROL_RTC_96 = 0x00000010,
+	DMA_CONTROL_RTC_128 = 0x00000018,
+};
+#define DMA_CONTROL_TC_RX_MASK		0xffffffe7
+
+#define DMA_CONTROL_OSF			0x00000004	/* Operate on second frame */
+
+/* MMC registers offset */
+#define GMAC_MMC_CTRL			0x100
+#define GMAC_MMC_RX_INTR		0x104
+#define GMAC_MMC_TX_INTR		0x108
+#define GMAC_MMC_RX_CSUM_OFFLOAD	0x208
+#define GMAC_EXTHASH_BASE		0x500
+
+extern const struct stmmac_dma_ops dwegmac_dma_ops;
+#endif /* __DWEGMAC_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c b/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
new file mode 100644
index 000000000000..4e0c8731adfb
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/crc32.h>
+#include <linux/slab.h>
+#include <linux/ethtool.h>
+#include <linux/io.h>
+#include "stmmac.h"
+#include "stmmac_pcs.h"
+#include "dwegmac.h"
+
+static void dwegmac_core_init(struct mac_device_info *hw,
+			      struct net_device *dev)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value = readl(ioaddr + GMAC_CONTROL);
+	int mtu = dev->mtu;
+
+	/* Configure GMAC core */
+	value |= GMAC_CORE_INIT;
+
+	if (mtu > 1500)
+		value |= GMAC_CONTROL_2K;
+	if (mtu > 2000)
+		value |= GMAC_CONTROL_JE;
+
+	if (hw->ps) {
+		value |= GMAC_CONTROL_TE;
+
+		value &= ~hw->link.speed_mask;
+		switch (hw->ps) {
+		case SPEED_1000:
+			value |= hw->link.speed1000;
+			break;
+		case SPEED_100:
+			value |= hw->link.speed100;
+			break;
+		case SPEED_10:
+			value |= hw->link.speed10;
+			break;
+		}
+	}
+
+	writel(value, ioaddr + GMAC_CONTROL);
+
+	/* Mask GMAC interrupts */
+	value = GMAC_INT_DEFAULT_MASK;
+
+	if (hw->pcs)
+		value &= ~GMAC_INT_DISABLE_PCS;
+
+	writel(value, ioaddr + GMAC_INT_MASK);
+
+#ifdef STMMAC_VLAN_TAG_USED
+	/* Tag detection without filtering */
+	writel(0x0, ioaddr + GMAC_VLAN_TAG);
+#endif
+}
+
+static int dwegmac_rx_ipc_enable(struct mac_device_info *hw)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value = readl(ioaddr + GMAC_CONTROL);
+
+	if (hw->rx_csum)
+		value |= GMAC_CONTROL_IPC;
+	else
+		value &= ~GMAC_CONTROL_IPC;
+
+	writel(value, ioaddr + GMAC_CONTROL);
+
+	value = readl(ioaddr + GMAC_CONTROL);
+
+	return !!(value & GMAC_CONTROL_IPC);
+}
+
+static void dwegmac_dump_regs(struct mac_device_info *hw, u32 *reg_space)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	int i;
+
+	for (i = 0; i < 55; i++)
+		reg_space[i] = readl(ioaddr + i * 4);
+}
+
+static void dwegmac_set_umac_addr(struct stmmac_priv *priv,
+				  struct mac_device_info *hw,
+				  const unsigned char *addr,
+				  unsigned int reg_n)
+{
+	void __iomem *ioaddr = hw->pcsr;
+
+	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+			    GMAC_ADDR_LOW(reg_n));
+}
+
+static void dwegmac_get_umac_addr(struct stmmac_priv *priv,
+				  struct mac_device_info *hw,
+				  unsigned char *addr,
+				  unsigned int reg_n)
+{
+	void __iomem *ioaddr = hw->pcsr;
+
+	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+			    GMAC_ADDR_LOW(reg_n));
+}
+
+static void dwegmac_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
+			       int mcbitslog2)
+{
+	int numhashregs, regs;
+
+	switch (mcbitslog2) {
+	case 6:
+		writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);
+		writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);
+		return;
+	case 7:
+		numhashregs = 4;
+		break;
+	case 8:
+		numhashregs = 8;
+		break;
+	default:
+		pr_debug("STMMAC: err in setting multicast filter\n");
+		return;
+	}
+	for (regs = 0; regs < numhashregs; regs++)
+		writel(mcfilterbits[regs],
+		       ioaddr + GMAC_EXTHASH_BASE + regs * 4);
+}
+
+static void dwegmac_set_filter(struct stmmac_priv *priv,
+			       struct mac_device_info *hw,
+			       struct net_device *dev)
+{
+	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
+	unsigned int value = 0;
+	unsigned int perfect_addr_number = hw->unicast_filter_entries;
+	u32 mc_filter[8];
+	int mcbitslog2 = hw->mcast_bits_log2;
+
+	pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
+		 netdev_mc_count(dev), netdev_uc_count(dev));
+
+	memset(mc_filter, 0, sizeof(mc_filter));
+
+	if (dev->flags & IFF_PROMISC) {
+		value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
+	} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
+		/* Fall back to all multicast if we've no filter */
+		value = GMAC_FRAME_FILTER_PM;
+	} else if (!netdev_mc_empty(dev)) {
+		struct netdev_hw_addr *ha;
+
+		/* Hash filter for multicast */
+		value = GMAC_FRAME_FILTER_HMC;
+
+		netdev_for_each_mc_addr(ha, dev) {
+			/* The upper n bits of the calculated CRC are used to
+			 * index the contents of the hash table. The number of
+			 * bits used depends on the hardware configuration
+			 * selected at core configuration time.
+			 */
+			int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
+					      ETH_ALEN)) >>
+					      (32 - mcbitslog2);
+			/* The most significant bit determines the register to
+			 * use (H/L) while the other 5 bits determine the bit
+			 * within the register.
+			 */
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+		}
+	}
+
+	value |= GMAC_FRAME_FILTER_HPF;
+	dwegmac_set_mchash(ioaddr, mc_filter, mcbitslog2);
+
+	/* Handle multiple unicast addresses (perfect filtering) */
+	if (netdev_uc_count(dev) > perfect_addr_number) {
+		/* Switch to promiscuous mode if more than unicast
+		 * addresses are requested than supported by hardware.
+		 */
+		value |= GMAC_FRAME_FILTER_PR;
+	} else {
+		int reg = 1;
+		struct netdev_hw_addr *ha;
+
+		netdev_for_each_uc_addr(ha, dev) {
+			stmmac_set_mac_addr(ioaddr, ha->addr,
+					    GMAC_ADDR_HIGH(reg),
+					    GMAC_ADDR_LOW(reg));
+			reg++;
+		}
+
+		while (reg < perfect_addr_number) {
+			writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+			writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+			reg++;
+		}
+	}
+
+#ifdef FRAME_FILTER_DEBUG
+	/* Enable Receive all mode (to debug filtering_fail errors) */
+	value |= GMAC_FRAME_FILTER_RA;
+#endif
+	writel(value, ioaddr + GMAC_FRAME_FILTER);
+}
+
+static void dwegmac_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
+			      unsigned int fc, unsigned int pause_time,
+			      u32 tx_cnt)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	/* Set flow such that DZPQ in Mac Register 6 is 0,
+	 * and unicast pause detect is enabled.
+	 */
+	unsigned int flow = GMAC_FLOW_CTRL_UP;
+
+	pr_debug("GMAC Flow-Control:\n");
+	if (fc & FLOW_RX) {
+		pr_debug("\tReceive Flow-Control ON\n");
+		flow |= GMAC_FLOW_CTRL_RFE;
+	}
+	if (fc & FLOW_TX) {
+		pr_debug("\tTransmit Flow-Control ON\n");
+		flow |= GMAC_FLOW_CTRL_TFE;
+	}
+
+	if (duplex) {
+		pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
+		flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
+	}
+
+	writel(flow, ioaddr + GMAC_FLOW_CTRL);
+}
+
+static void dwegmac_pmt(struct mac_device_info *hw, unsigned long mode)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	unsigned int pmt = 0;
+
+	if (mode & WAKE_MAGIC) {
+		pr_debug("GMAC: WOL Magic frame\n");
+		pmt |= power_down | magic_pkt_en;
+	}
+	if (mode & WAKE_UCAST) {
+		pr_debug("GMAC: WOL on global unicast\n");
+		pmt |= power_down | global_unicast | wake_up_frame_en;
+	}
+
+	writel(pmt, ioaddr + GMAC_PMT);
+}
+
+/* RGMII or SMII interface */
+static void dwegmac_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
+{
+	u32 status;
+
+	status = readl(ioaddr + GMAC_RGSMIIIS);
+	x->irq_rgmii_n++;
+
+	/* Check the link status */
+	if (status & GMAC_RGSMIIIS_LNKSTS) {
+		int speed_value;
+
+		x->pcs_link = 1;
+
+		speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
+			       GMAC_RGSMIIIS_SPEED_SHIFT);
+		if (speed_value == GMAC_RGSMIIIS_SPEED_125)
+			x->pcs_speed = SPEED_1000;
+		else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
+			x->pcs_speed = SPEED_100;
+		else
+			x->pcs_speed = SPEED_10;
+
+		x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
+
+		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
+			x->pcs_duplex ? "Full" : "Half");
+	} else {
+		x->pcs_link = 0;
+		pr_info("Link is Down\n");
+	}
+}
+
+static int dwegmac_irq_status(struct mac_device_info *hw,
+			      struct stmmac_extra_stats *x)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+	u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
+	int ret = 0;
+
+	/* Discard masked bits */
+	intr_status &= ~intr_mask;
+
+	/* Not used events (e.g. MMC interrupts) are not handled. */
+	if ((intr_status & GMAC_INT_STATUS_MMCTIS))
+		x->mmc_tx_irq_n++;
+	if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
+		x->mmc_rx_irq_n++;
+	if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
+		x->mmc_rx_csum_offload_irq_n++;
+	if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
+		/* clear the PMT bits 5 and 6 by reading the PMT status reg */
+		readl(ioaddr + GMAC_PMT);
+		x->irq_receive_pmt_irq_n++;
+	}
+
+	/* MAC tx/rx EEE LPI entry/exit interrupts */
+	if (intr_status & GMAC_INT_STATUS_LPIIS) {
+		/* Clean LPI interrupt by reading the Reg 12 */
+		ret = readl(ioaddr + LPI_CTRL_STATUS);
+
+		if (ret & LPI_CTRL_STATUS_TLPIEN)
+			x->irq_tx_path_in_lpi_mode_n++;
+		if (ret & LPI_CTRL_STATUS_TLPIEX)
+			x->irq_tx_path_exit_lpi_mode_n++;
+		if (ret & LPI_CTRL_STATUS_RLPIEN)
+			x->irq_rx_path_in_lpi_mode_n++;
+		if (ret & LPI_CTRL_STATUS_RLPIEX)
+			x->irq_rx_path_exit_lpi_mode_n++;
+	}
+
+	dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
+
+	if (intr_status & PCS_RGSMIIIS_IRQ)
+		dwegmac_rgsmii(ioaddr, x);
+
+	return ret;
+}
+
+static void dwegmac_set_eee_mode(struct mac_device_info *hw,
+				 bool en_tx_lpi_clockgating)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value;
+
+	/*TODO - en_tx_lpi_clockgating treatment */
+
+	/* Enable the link status receive on RGMII, SGMII ore SMII
+	 * receive path and instruct the transmit to enter in LPI
+	 * state.
+	 */
+	value = readl(ioaddr + LPI_CTRL_STATUS);
+	value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
+	writel(value, ioaddr + LPI_CTRL_STATUS);
+}
+
+static void dwegmac_reset_eee_mode(struct mac_device_info *hw)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value;
+
+	value = readl(ioaddr + LPI_CTRL_STATUS);
+	value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
+	writel(value, ioaddr + LPI_CTRL_STATUS);
+}
+
+static void dwegmac_set_eee_pls(struct mac_device_info *hw, int link)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value;
+
+	value = readl(ioaddr + LPI_CTRL_STATUS);
+
+	if (link)
+		value |= LPI_CTRL_STATUS_PLS;
+	else
+		value &= ~LPI_CTRL_STATUS_PLS;
+
+	writel(value, ioaddr + LPI_CTRL_STATUS);
+}
+
+static void dwegmac_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
+
+	/* Program the timers in the LPI timer control register:
+	 * LS: minimum time (ms) for which the link
+	 *  status from PHY should be ok before transmitting
+	 *  the LPI pattern.
+	 * TW: minimum time (us) for which the core waits
+	 *  after it has stopped transmitting the LPI pattern.
+	 */
+	writel(value, ioaddr + LPI_TIMER_CTRL);
+}
+
+static void dwegmac_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
+			     bool loopback)
+{
+	dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
+}
+
+static void dwegmac_rane(void __iomem *ioaddr, bool restart)
+{
+	dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
+}
+
+static void dwegmac_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
+{
+	dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
+}
+
+static void dwegmac_debug(struct stmmac_priv *priv, void __iomem *ioaddr,
+			  struct stmmac_extra_stats *x,
+			  u32 rx_queues, u32 tx_queues)
+{
+	u32 value = readl(ioaddr + GMAC_DEBUG);
+
+	if (value & GMAC_DEBUG_TXSTSFSTS)
+		x->mtl_tx_status_fifo_full++;
+	if (value & GMAC_DEBUG_TXFSTS)
+		x->mtl_tx_fifo_not_empty++;
+	if (value & GMAC_DEBUG_TWCSTS)
+		x->mmtl_fifo_ctrl++;
+	if (value & GMAC_DEBUG_TRCSTS_MASK) {
+		u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK)
+			     >> GMAC_DEBUG_TRCSTS_SHIFT;
+		if (trcsts == GMAC_DEBUG_TRCSTS_WRITE)
+			x->mtl_tx_fifo_read_ctrl_write++;
+		else if (trcsts == GMAC_DEBUG_TRCSTS_TXW)
+			x->mtl_tx_fifo_read_ctrl_wait++;
+		else if (trcsts == GMAC_DEBUG_TRCSTS_READ)
+			x->mtl_tx_fifo_read_ctrl_read++;
+		else
+			x->mtl_tx_fifo_read_ctrl_idle++;
+	}
+	if (value & GMAC_DEBUG_TXPAUSED)
+		x->mac_tx_in_pause++;
+	if (value & GMAC_DEBUG_TFCSTS_MASK) {
+		u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK)
+			      >> GMAC_DEBUG_TFCSTS_SHIFT;
+
+		if (tfcsts == GMAC_DEBUG_TFCSTS_XFER)
+			x->mac_tx_frame_ctrl_xfer++;
+		else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE)
+			x->mac_tx_frame_ctrl_pause++;
+		else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT)
+			x->mac_tx_frame_ctrl_wait++;
+		else
+			x->mac_tx_frame_ctrl_idle++;
+	}
+	if (value & GMAC_DEBUG_TPESTS)
+		x->mac_gmii_tx_proto_engine++;
+	if (value & GMAC_DEBUG_RXFSTS_MASK) {
+		u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK)
+			     >> GMAC_DEBUG_RRCSTS_SHIFT;
+
+		if (rxfsts == GMAC_DEBUG_RXFSTS_FULL)
+			x->mtl_rx_fifo_fill_level_full++;
+		else if (rxfsts == GMAC_DEBUG_RXFSTS_AT)
+			x->mtl_rx_fifo_fill_above_thresh++;
+		else if (rxfsts == GMAC_DEBUG_RXFSTS_BT)
+			x->mtl_rx_fifo_fill_below_thresh++;
+		else
+			x->mtl_rx_fifo_fill_level_empty++;
+	}
+	if (value & GMAC_DEBUG_RRCSTS_MASK) {
+		u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >>
+			     GMAC_DEBUG_RRCSTS_SHIFT;
+
+		if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH)
+			x->mtl_rx_fifo_read_ctrl_flush++;
+		else if (rrcsts == GMAC_DEBUG_RRCSTS_RSTAT)
+			x->mtl_rx_fifo_read_ctrl_read_data++;
+		else if (rrcsts == GMAC_DEBUG_RRCSTS_RDATA)
+			x->mtl_rx_fifo_read_ctrl_status++;
+		else
+			x->mtl_rx_fifo_read_ctrl_idle++;
+	}
+	if (value & GMAC_DEBUG_RWCSTS)
+		x->mtl_rx_fifo_ctrl_active++;
+	if (value & GMAC_DEBUG_RFCFCSTS_MASK)
+		x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK)
+					    >> GMAC_DEBUG_RFCFCSTS_SHIFT;
+	if (value & GMAC_DEBUG_RPESTS)
+		x->mac_gmii_rx_proto_engine++;
+}
+
+static void dwegmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+	u32 value = readl(ioaddr + GMAC_CONTROL);
+
+	if (enable)
+		value |= GMAC_CONTROL_LM;
+	else
+		value &= ~GMAC_CONTROL_LM;
+
+	writel(value, ioaddr + GMAC_CONTROL);
+}
+
+const struct stmmac_ops dwegmac_ops = {
+	.core_init = dwegmac_core_init,
+	.set_mac = stmmac_set_mac,
+	.rx_ipc = dwegmac_rx_ipc_enable,
+	.dump_regs = dwegmac_dump_regs,
+	.host_irq_status = dwegmac_irq_status,
+	.set_filter = dwegmac_set_filter,
+	.flow_ctrl = dwegmac_flow_ctrl,
+	.pmt = dwegmac_pmt,
+	.set_umac_addr = dwegmac_set_umac_addr,
+	.get_umac_addr = dwegmac_get_umac_addr,
+	.set_eee_mode = dwegmac_set_eee_mode,
+	.reset_eee_mode = dwegmac_reset_eee_mode,
+	.set_eee_timer = dwegmac_set_eee_timer,
+	.set_eee_pls = dwegmac_set_eee_pls,
+	.debug = dwegmac_debug,
+	.pcs_ctrl_ane = dwegmac_ctrl_ane,
+	.pcs_rane = dwegmac_rane,
+	.pcs_get_adv_lp = dwegmac_get_adv_lp,
+	.set_mac_loopback = dwegmac_set_mac_loopback,
+};
+
+int dwegmac_setup(struct stmmac_priv *priv)
+{
+	struct mac_device_info *mac = priv->hw;
+
+	dev_info(priv->device, "\tExtended DWMAC\n");
+
+	priv->dev->priv_flags |= IFF_UNICAST_FLT;
+	mac->pcsr = priv->ioaddr;
+	mac->multicast_filter_bins = priv->plat->multicast_filter_bins;
+	mac->unicast_filter_entries = priv->plat->unicast_filter_entries;
+	mac->mcast_bits_log2 = 0;
+
+	if (mac->multicast_filter_bins)
+		mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
+
+	mac->link.duplex = GMAC_CONTROL_DM;
+	mac->link.speed10 = GMAC_CONTROL_PS;
+	mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
+	mac->link.speed1000 = 0;
+	mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
+	mac->mii.addr = GMAC_MII_ADDR;
+	mac->mii.data = GMAC_MII_DATA;
+	mac->mii.addr_shift = 11;
+	mac->mii.addr_mask = 0x0000F800;
+	mac->mii.reg_shift = 6;
+	mac->mii.reg_mask = 0x000007C0;
+	mac->mii.clk_csr_shift = 2;
+	mac->mii.clk_csr_mask = GENMASK(5, 2);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
new file mode 100644
index 000000000000..9bb0564fbeff
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/io.h>
+#include "stmmac.h"
+#include "dwegmac.h"
+#include "dwegmac_dma.h"
+
+static int dwegmac_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
+{
+	u32 value = readl(ioaddr + DMA_BUS_MODE);
+
+	value |= DMA_BUS_MODE_SFT_RESET;
+	writel(value, ioaddr + DMA_BUS_MODE);
+
+	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+				 !(value & DMA_BUS_MODE_SFT_RESET),
+				 10000, 200000);
+}
+
+static void dwegmac_enable_dma_transmission(struct stmmac_priv *priv,
+					    void __iomem *ioaddr, u32 chan)
+{
+	writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));
+}
+
+static void dwegmac_enable_dma_irq(struct stmmac_priv *priv,
+				   void __iomem *ioaddr,
+				   u32 chan, bool rx, bool tx)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value |= DMA_INTR_DEFAULT_RX;
+	if (tx)
+		value |= DMA_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
+static void dwegmac_disable_dma_irq(struct stmmac_priv *priv,
+				    void __iomem *ioaddr,
+				    u32 chan, bool rx, bool tx)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (rx)
+		value &= ~DMA_INTR_DEFAULT_RX;
+	if (tx)
+		value &= ~DMA_INTR_DEFAULT_TX;
+
+	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
+static void dwegmac_dma_start_tx(struct stmmac_priv *priv,
+				 void __iomem *ioaddr, u32 chan)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+
+	value |= DMA_CONTROL_ST;
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+}
+
+static void dwegmac_dma_stop_tx(struct stmmac_priv *priv,
+				void __iomem *ioaddr, u32 chan)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+
+	value &= ~DMA_CONTROL_ST;
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+}
+
+static void dwegmac_dma_start_rx(struct stmmac_priv *priv,
+				 void __iomem *ioaddr, u32 chan)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+
+	value |= DMA_CONTROL_SR;
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+}
+
+static void dwegmac_dma_stop_rx(struct stmmac_priv *priv,
+				void __iomem *ioaddr, u32 chan)
+{
+	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+
+	value &= ~DMA_CONTROL_SR;
+	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+}
+
+static int dwegmac_dma_interrupt(struct stmmac_priv *priv,
+				 void __iomem *ioaddr,
+				 struct stmmac_extra_stats *x,
+				 u32 chan, u32 dir)
+{
+	int ret = 0;
+	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
+
+	if (dir == DMA_DIR_RX)
+		intr_status &= DMA_STATUS_MSK_RX;
+	else if (dir == DMA_DIR_TX)
+		intr_status &= DMA_STATUS_MSK_TX;
+
+	/* ABNORMAL interrupts */
+	if (unlikely(intr_status & (DMA_STATUS_TX_AIS | DMA_STATUS_RX_AIS))) {
+		if (unlikely(intr_status & DMA_STATUS_UNF)) {
+			ret = tx_hard_error_bump_tc;
+			x->tx_undeflow_irq++;
+		}
+		if (unlikely(intr_status & DMA_STATUS_TJT))
+			x->tx_jabber_irq++;
+
+		if (unlikely(intr_status & DMA_STATUS_OVF))
+			x->rx_overflow_irq++;
+
+		if (unlikely(intr_status & DMA_STATUS_RU))
+			x->rx_buf_unav_irq++;
+		if (unlikely(intr_status & DMA_STATUS_RPS))
+			x->rx_process_stopped_irq++;
+		if (unlikely(intr_status & DMA_STATUS_RWT))
+			x->rx_watchdog_irq++;
+		if (unlikely(intr_status & DMA_STATUS_ETI))
+			x->tx_early_irq++;
+		if (unlikely(intr_status & DMA_STATUS_TPS)) {
+			x->tx_process_stopped_irq++;
+			ret = tx_hard_error;
+		}
+		if (unlikely(intr_status &
+			     (DMA_STATUS_TX_FBI | DMA_STATUS_RX_FBI))) {
+			x->fatal_bus_error_irq++;
+			ret = tx_hard_error;
+		}
+	}
+	/* TX/RX NORMAL interrupts */
+	if (likely(intr_status & (DMA_STATUS_TX_NIS | DMA_STATUS_RX_NIS))) {
+		x->normal_irq_n++;
+		if (likely(intr_status & DMA_STATUS_RI)) {
+			u32 value = readl(ioaddr + DMA_INTR_ENA);
+			/* to schedule NAPI on real RIE event. */
+			if (likely(value & DMA_INTR_ENA_RIE)) {
+				x->rx_normal_irq_n++;
+				ret |= handle_rx;
+			}
+		}
+		if (likely(intr_status & DMA_STATUS_TI)) {
+			x->tx_normal_irq_n++;
+			ret |= handle_tx;
+		}
+		if (unlikely(intr_status & DMA_STATUS_ERI))
+			x->rx_early_irq++;
+	}
+
+	writel((intr_status & 0x7ffff), ioaddr + DMA_CHAN_STATUS(chan));
+
+	return ret;
+}
+
+static void dwegmac_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
+			    struct stmmac_axi *axi)
+{
+	u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
+	int i;
+
+	pr_info("dwegmac: Master AXI performs %s burst length\n",
+		!(value & DMA_AXI_UNDEF) ? "fixed" : "any");
+
+	if (axi->axi_lpi_en)
+		value |= DMA_AXI_EN_LPI;
+	if (axi->axi_xit_frm)
+		value |= DMA_AXI_LPI_XIT_FRM;
+
+	if (priv->plat->dma_cfg->dma64) {
+		value &= ~DMA_AXI_WR_OSR64_LMT;
+		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR64_LMT_MASK) <<
+			 DMA_AXI_WR_OSR64_LMT_SHIFT;
+
+		value &= ~DMA_AXI_RD_OSR64_LMT;
+		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR64_LMT_MASK) <<
+			 DMA_AXI_RD_OSR64_LMT_SHIFT;
+	} else {
+		value &= ~DMA_AXI_WR_OSR_LMT;
+		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
+			 DMA_AXI_WR_OSR_LMT_SHIFT;
+
+		value &= ~DMA_AXI_RD_OSR_LMT;
+		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
+			 DMA_AXI_RD_OSR_LMT_SHIFT;
+	}
+
+	/* Depending on the UNDEF bit the Master AXI will perform any burst
+	 * length according to the BLEN programmed (by default all BLEN are
+	 * set).
+	 */
+	for (i = 0; i < AXI_BLEN; i++) {
+		switch (axi->axi_blen[i]) {
+		case 256:
+			value |= DMA_AXI_BLEN256;
+			break;
+		case 128:
+			value |= DMA_AXI_BLEN128;
+			break;
+		case 64:
+			value |= DMA_AXI_BLEN64;
+			break;
+		case 32:
+			value |= DMA_AXI_BLEN32;
+			break;
+		case 16:
+			value |= DMA_AXI_BLEN16;
+			break;
+		case 8:
+			value |= DMA_AXI_BLEN8;
+			break;
+		case 4:
+			value |= DMA_AXI_BLEN4;
+			break;
+		}
+	}
+
+	writel(value, ioaddr + DMA_AXI_BUS_MODE);
+}
+
+static void dwegmac_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
+			     struct stmmac_dma_cfg *dma_cfg, int atds)
+{
+	u32 value = readl(ioaddr + DMA_BUS_MODE);
+	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
+	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+
+	/* Set the DMA PBL (Programmable Burst Length) mode.
+	 *
+	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
+	 * post 3.5 mode bit acts as 8*PBL.
+	 */
+	if (dma_cfg->pblx8)
+		value |= DMA_BUS_MODE_MAXPBL;
+	value |= DMA_BUS_MODE_USP;
+	value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
+	value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
+	value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
+
+	/* Set the Fixed burst mode */
+	if (dma_cfg->fixed_burst)
+		value |= DMA_BUS_MODE_FB;
+
+	/* Mixed Burst has no effect when fb is set */
+	if (dma_cfg->mixed_burst)
+		value |= DMA_BUS_MODE_MB;
+
+	if (atds)
+		value |= DMA_BUS_MODE_ATDS;
+
+	if (dma_cfg->aal)
+		value |= DMA_BUS_MODE_AAL;
+
+	writel(value, ioaddr + DMA_BUS_MODE);
+
+	/* Mask interrupts by writing to CSR7 */
+	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+}
+
+static void dwegmac_dma_init_channel(struct stmmac_priv *priv,
+				     void __iomem *ioaddr,
+				     struct stmmac_dma_cfg *dma_cfg,
+				     u32 chan)
+{
+	u32 value;
+	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
+	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+
+	if (!priv->plat->multi_msi_en)
+		return;
+
+	/* common channel control register config */
+	value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
+
+	/* Set the DMA PBL (Programmable Burst Length) mode.
+	 *
+	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
+	 * post 3.5 mode bit acts as 8*PBL.
+	 */
+	if (dma_cfg->pblx8)
+		value |= DMA_BUS_MODE_MAXPBL;
+	value |= DMA_BUS_MODE_USP;
+	value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
+	value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
+	value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
+
+	/* Set the Fixed burst mode */
+	if (dma_cfg->fixed_burst)
+		value |= DMA_BUS_MODE_FB;
+
+	/* Mixed Burst has no effect when fb is set */
+	if (dma_cfg->mixed_burst)
+		value |= DMA_BUS_MODE_MB;
+
+	value |= DMA_BUS_MODE_ATDS;
+
+	if (dma_cfg->aal)
+		value |= DMA_BUS_MODE_AAL;
+
+	writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
+
+	/* Mask interrupts by writing to CSR7 */
+	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
+
+	if (dma_cfg->dma64)
+		writel(0x100, ioaddr + DMA_CHAN_NEWFUNC_CONFIG(chan));
+}
+
+static void dwegmac_dma_init_rx(struct stmmac_priv *priv,
+				void __iomem *ioaddr,
+				struct stmmac_dma_cfg *dma_cfg,
+				dma_addr_t dma_rx_phy, u32 chan)
+{
+	if (dma_cfg->dma64) {
+		writel(lower_32_bits(dma_rx_phy), ioaddr +
+		       DMA_CHAN_RCV_BASE_ADDR64(chan));
+		writel(upper_32_bits(dma_rx_phy), ioaddr +
+		       DMA_CHAN_RCV_BASE_ADDR64_HI(chan));
+		writel(upper_32_bits(dma_rx_phy), ioaddr +
+		       DMA_RCV_BASE_ADDR64_HI_SHADOW1);
+		writel(upper_32_bits(dma_rx_phy), ioaddr +
+		       DMA_RCV_BASE_ADDR64_HI_SHADOW2);
+	} else {
+		writel(lower_32_bits(dma_rx_phy), ioaddr +
+		       DMA_CHAN_RCV_BASE_ADDR(chan));
+	}
+}
+
+static void dwegmac_dma_init_tx(struct stmmac_priv *priv,
+				void __iomem *ioaddr,
+				struct stmmac_dma_cfg *dma_cfg,
+				dma_addr_t dma_tx_phy, u32 chan)
+{
+	if (dma_cfg->dma64) {
+		writel(lower_32_bits(dma_tx_phy), ioaddr +
+		       DMA_CHAN_TX_BASE_ADDR64(chan));
+		writel(upper_32_bits(dma_tx_phy), ioaddr +
+		       DMA_CHAN_TX_BASE_ADDR64_HI(chan));
+	} else {
+		writel(lower_32_bits(dma_tx_phy), ioaddr +
+		       DMA_CHAN_TX_BASE_ADDR(chan));
+	}
+}
+
+static u32 dwegmac_configure_fc(u32 csr6, int rxfifosz)
+{
+	csr6 &= ~DMA_CONTROL_RFA_MASK;
+	csr6 &= ~DMA_CONTROL_RFD_MASK;
+
+	/* Leave flow control disabled if receive fifo size is less than
+	 * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
+	 * and send XON when 2K less than full.
+	 */
+	if (rxfifosz < 4096) {
+		csr6 &= ~DMA_CONTROL_EFC;
+		pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
+			 rxfifosz);
+	} else {
+		csr6 |= DMA_CONTROL_EFC;
+		csr6 |= RFA_FULL_MINUS_1K;
+		csr6 |= RFD_FULL_MINUS_2K;
+	}
+	return csr6;
+}
+
+static void dwegmac_dma_operation_mode_rx(struct stmmac_priv *priv,
+					  void __iomem *ioaddr, int mode,
+					  u32 channel, int fifosz, u8 qmode)
+{
+	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
+
+	if (mode == SF_DMA_MODE) {
+		pr_debug("GMAC: enable RX store and forward mode\n");
+		csr6 |= DMA_CONTROL_RSF;
+	} else {
+		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
+		csr6 &= ~DMA_CONTROL_RSF;
+		csr6 &= DMA_CONTROL_TC_RX_MASK;
+		if (mode <= 32)
+			csr6 |= DMA_CONTROL_RTC_32;
+		else if (mode <= 64)
+			csr6 |= DMA_CONTROL_RTC_64;
+		else if (mode <= 96)
+			csr6 |= DMA_CONTROL_RTC_96;
+		else
+			csr6 |= DMA_CONTROL_RTC_128;
+	}
+
+	/* Configure flow control based on rx fifo size */
+	csr6 = dwegmac_configure_fc(csr6, fifosz);
+
+	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
+}
+
+static void dwegmac_dma_operation_mode_tx(struct stmmac_priv *priv,
+					  void __iomem *ioaddr, int mode,
+					  u32 channel, int fifosz, u8 qmode)
+{
+	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
+
+	if (mode == SF_DMA_MODE) {
+		pr_debug("GMAC: enable TX store and forward mode\n");
+		/* Transmit COE type 2 cannot be done in cut-through mode. */
+		csr6 |= DMA_CONTROL_TSF;
+		/* Operating on second frame increase the performance
+		 * especially when transmit store-and-forward is used.
+		 */
+		csr6 |= DMA_CONTROL_OSF;
+	} else {
+		pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
+		csr6 &= ~DMA_CONTROL_TSF;
+		csr6 &= DMA_CONTROL_TC_TX_MASK;
+		/* Set the transmit threshold */
+		if (mode <= 32)
+			csr6 |= DMA_CONTROL_TTC_32;
+		else if (mode <= 64)
+			csr6 |= DMA_CONTROL_TTC_64;
+		else if (mode <= 128)
+			csr6 |= DMA_CONTROL_TTC_128;
+		else if (mode <= 192)
+			csr6 |= DMA_CONTROL_TTC_192;
+		else
+			csr6 |= DMA_CONTROL_TTC_256;
+	}
+
+	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
+}
+
+static void dwegmac_dump_dma_regs(struct stmmac_priv *priv,
+				  void __iomem *ioaddr, u32 *reg_space)
+{
+	int i;
+
+	for (i = 0; i < NUM_DWEGMAC_DMA_REGS; i++)
+		if (i < 12 || i > 17)
+			reg_space[DMA_BUS_MODE / 4 + i] =
+				readl(ioaddr + DMA_BUS_MODE + i * 4);
+}
+
+static int dwegmac_get_hw_feature(struct stmmac_priv *priv,
+				  void __iomem *ioaddr,
+				  struct dma_features *dma_cap)
+{
+	u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
+
+	if (!hw_cap) {
+		/* 0x00000000 is the value read on old hardware that does not
+		 * implement this register
+		 */
+		return -EOPNOTSUPP;
+	}
+
+	dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
+	dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
+	dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
+	dma_cap->hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
+	dma_cap->multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
+	dma_cap->pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
+	dma_cap->sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
+	dma_cap->pmt_remote_wake_up = (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
+	dma_cap->pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
+	/* MMC */
+	dma_cap->rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
+	/* IEEE 1588-2002 */
+	dma_cap->time_stamp =
+	    (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
+	/* IEEE 1588-2008 */
+	dma_cap->atime_stamp = (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
+	/* 802.3az - Energy-Efficient Ethernet (EEE) */
+	dma_cap->eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
+	dma_cap->av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
+	/* TX and RX csum */
+	dma_cap->tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
+	dma_cap->rx_coe_type1 = (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
+	dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
+	dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
+	/* TX and RX number of channels */
+	dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+	dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+	/* Alternate (enhanced) DESC mode */
+	dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
+
+	return 0;
+}
+
+static void dwegmac_rx_watchdog(struct stmmac_priv *priv,
+				void __iomem *ioaddr, u32 riwt, u32 queue)
+{
+	writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
+}
+
+const struct stmmac_dma_ops dwegmac_dma_ops = {
+	.reset = dwegmac_dma_reset,
+	.init = dwegmac_dma_init,
+	.init_chan = dwegmac_dma_init_channel,
+	.init_rx_chan = dwegmac_dma_init_rx,
+	.init_tx_chan = dwegmac_dma_init_tx,
+	.axi = dwegmac_dma_axi,
+	.dump_regs = dwegmac_dump_dma_regs,
+	.dma_rx_mode = dwegmac_dma_operation_mode_rx,
+	.dma_tx_mode = dwegmac_dma_operation_mode_tx,
+	.enable_dma_transmission = dwegmac_enable_dma_transmission,
+	.enable_dma_irq = dwegmac_enable_dma_irq,
+	.disable_dma_irq = dwegmac_disable_dma_irq,
+	.start_tx = dwegmac_dma_start_tx,
+	.stop_tx = dwegmac_dma_stop_tx,
+	.start_rx = dwegmac_dma_start_rx,
+	.stop_rx = dwegmac_dma_stop_rx,
+	.dma_interrupt = dwegmac_dma_interrupt,
+	.get_hw_feature = dwegmac_get_hw_feature,
+	.rx_watchdog = dwegmac_rx_watchdog,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
new file mode 100644
index 000000000000..aadc13eae502
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __DWEGMAC_DMA_H__
+#define __DWEGMAC_DMA_H__
+
+/* DMA CRS Control and Status Register Mapping */
+#define DMA_BUS_MODE			0x00001000	/* Bus Mode */
+#define DMA_XMT_POLL_DEMAND		0x00001004	/* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND		0x00001008	/* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR		0x0000100c	/* Receive List Base */
+#define DMA_RCV_BASE_ADDR64		0x00001090
+#define DMA_RCV_BASE_ADDR64_HI		0x00001094
+#define DMA_RCV_BASE_ADDR64_HI_SHADOW1	0x00001068
+#define DMA_RCV_BASE_ADDR64_HI_SHADOW2	0x000010a8
+#define DMA_TX_BASE_ADDR		0x00001010	/* Transmit List Base */
+#define DMA_TX_BASE_ADDR64		0x00001098
+#define DMA_TX_BASE_ADDR64_HI		0x0000109c
+#define DMA_STATUS			0x00001014	/* Status Register */
+#define DMA_CONTROL			0x00001018	/* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA			0x0000101c	/* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR		0x00001020	/* Missed Frame Counter */
+#define DMA_NEWFUNC_CONFIG		0x00001080	/* New Function Config */
+
+/* SW Reset */
+#define DMA_BUS_MODE_SFT_RESET		0x00000001	/* Software Reset */
+
+/* Rx watchdog register */
+#define DMA_RX_WATCHDOG			0x00001024
+
+/* AXI Master Bus Mode */
+#define DMA_AXI_BUS_MODE		0x00001028
+
+#define DMA_AXI_EN_LPI			BIT(31)
+#define DMA_AXI_LPI_XIT_FRM		BIT(30)
+#define DMA_AXI_WR_OSR_LMT		GENMASK(23, 20)
+#define DMA_AXI_WR_OSR_LMT_SHIFT	20
+#define DMA_AXI_WR_OSR_LMT_MASK		0xf
+#define DMA_AXI_RD_OSR_LMT		GENMASK(19, 16)
+#define DMA_AXI_RD_OSR_LMT_SHIFT	16
+#define DMA_AXI_RD_OSR_LMT_MASK		0xf
+#define DMA_AXI_WR_OSR64_LMT		GENMASK(21, 20)
+#define DMA_AXI_WR_OSR64_LMT_SHIFT	20
+#define DMA_AXI_WR_OSR64_LMT_MASK	0x3
+#define DMA_AXI_RD_OSR64_LMT		GENMASK(17, 16)
+#define DMA_AXI_RD_OSR64_LMT_SHIFT	16
+#define DMA_AXI_RD_OSR64_LMT_MASK	0x3
+
+#define DMA_AXI_OSR_MAX			0xf
+#define DMA_AXI_MAX_OSR_LIMIT		((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
+					 (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
+#define DMA_AXI_OSR64_MAX		0x3
+#define DMA_AXI_MAX_OSR64_LIMIT		((DMA_AXI_OSR64_MAX << DMA_AXI_WR_OSR64_LMT_SHIFT) | \
+					 (DMA_AXI_OSR64_MAX << DMA_AXI_RD_OSR64_LMT_SHIFT))
+#define	DMA_AXI_1KBBE			BIT(13)
+#define DMA_AXI_AAL			BIT(12)
+#define DMA_AXI_BLEN256			BIT(7)
+#define DMA_AXI_BLEN128			BIT(6)
+#define DMA_AXI_BLEN64			BIT(5)
+#define DMA_AXI_BLEN32			BIT(4)
+#define DMA_AXI_BLEN16			BIT(3)
+#define DMA_AXI_BLEN8			BIT(2)
+#define DMA_AXI_BLEN4			BIT(1)
+#define DMA_BURST_LEN_DEFAULT		(DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
+					 DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
+					 DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
+					 DMA_AXI_BLEN4)
+
+#define DMA_AXI_UNDEF			BIT(0)
+
+#define DMA_AXI_BURST_LEN_MASK		0x000000fe
+
+#define DMA_CUR_TX_BUF_ADDR		0x00001050	/* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR		0x00001054	/* Current Host Rx Buffer */
+#define DMA_HW_FEATURE			0x00001058	/* HW Feature Register */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST			0x00002000	/* Start/Stop Transmission */
+#define DMA_CONTROL_SR			0x00000002	/* Start/Stop Receive */
+
+/* DMA Normal interrupt */
+#define DMA_INTR_ENA_NIE		0x00060000	/* Normal Summary */
+#define DMA_INTR_ENA_TIE		0x00000001	/* Transmit Interrupt */
+#define DMA_INTR_ENA_TUE		0x00000004	/* Transmit Buffer Unavailable */
+#define DMA_INTR_ENA_RIE		0x00000040	/* Receive Interrupt */
+#define DMA_INTR_ENA_ERE		0x00004000	/* Early Receive */
+
+#define DMA_INTR_NORMAL			(DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
+					 DMA_INTR_ENA_TIE)
+
+/* DMA Abnormal interrupt */
+#define DMA_INTR_ENA_AIE		0x00018000	/* Abnormal Summary */
+#define DMA_INTR_ENA_FBE		0x00002000	/* Fatal Bus Error */
+#define DMA_INTR_ENA_ETE		0x00000400	/* Early Transmit */
+#define DMA_INTR_ENA_RWE		0x00000200	/* Receive Watchdog */
+#define DMA_INTR_ENA_RSE		0x00000100	/* Receive Stopped */
+#define DMA_INTR_ENA_RUE		0x00000080	/* Receive Buffer Unavailable */
+#define DMA_INTR_ENA_UNE		0x00000020	/* Tx Underflow */
+#define DMA_INTR_ENA_OVE		0x00000010	/* Receive Overflow */
+#define DMA_INTR_ENA_TJE		0x00000008	/* Transmit Jabber */
+#define DMA_INTR_ENA_TSE		0x00000002	/* Transmit Stopped */
+
+#define DMA_INTR_ABNORMAL		(DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
+					 DMA_INTR_ENA_UNE)
+
+/* DMA default interrupt mask */
+#define DMA_INTR_DEFAULT_MASK		(DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+#define DMA_INTR_DEFAULT_RX		(DMA_INTR_ENA_RIE)
+#define DMA_INTR_DEFAULT_TX		(DMA_INTR_ENA_TIE)
+
+/* DMA Status register defines */
+#define DMA_STATUS_GLPII		0x10000000	/* GMAC LPI interrupt */
+#define DMA_STATUS_EB_MASK		0x0e000000	/* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT		0x00080000	/* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT		0x00100000	/* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK		0x01c00000	/* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT		22
+#define DMA_STATUS_RS_MASK		0x00380000	/* Receive Process State */
+#define DMA_STATUS_RS_SHIFT		19
+#define DMA_STATUS_TX_NIS		0x00040000	/* Normal Tx Interrupt Summary */
+#define DMA_STATUS_RX_NIS		0x00020000	/* Normal Rx Interrupt Summary */
+#define DMA_STATUS_TX_AIS		0x00010000	/* Abnormal Tx Interrupt Summary */
+#define DMA_STATUS_RX_AIS		0x00008000	/* Abnormal Rx Interrupt Summary */
+#define DMA_STATUS_ERI			0x00004000	/* Early Receive Interrupt */
+#define DMA_STATUS_TX_FBI		0x00002000	/* Fatal Tx Bus Error Interrupt */
+#define DMA_STATUS_RX_FBI		0x00001000	/* Fatal Rx Bus Error Interrupt */
+#define DMA_STATUS_ETI			0x00000400	/* Early Transmit Interrupt */
+#define DMA_STATUS_RWT			0x00000200	/* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS			0x00000100	/* Receive Process Stopped */
+#define DMA_STATUS_RU			0x00000080	/* Receive Buffer Unavailable */
+#define DMA_STATUS_RI			0x00000040	/* Receive Interrupt */
+#define DMA_STATUS_UNF			0x00000020	/* Transmit Underflow */
+#define DMA_STATUS_OVF			0x00000010	/* Receive Overflow */
+#define DMA_STATUS_TJT			0x00000008	/* Transmit Jabber Timeout */
+#define DMA_STATUS_TU			0x00000004	/* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS			0x00000002	/* Transmit Process Stopped */
+#define DMA_STATUS_TI			0x00000001	/* Transmit Interrupt */
+#define DMA_CONTROL_FTF			0x00100000	/* Flush transmit FIFO */
+
+#define DMA_STATUS_MSK_RX_COMMON	(DMA_STATUS_RX_NIS | \
+					 DMA_STATUS_RX_AIS | \
+					 DMA_STATUS_RX_FBI)
+
+#define DMA_STATUS_MSK_TX_COMMON	(DMA_STATUS_TX_NIS | \
+					 DMA_STATUS_TX_AIS | \
+					 DMA_STATUS_TX_FBI)
+
+#define DMA_STATUS_MSK_RX		(DMA_STATUS_ERI | \
+					 DMA_STATUS_RWT | \
+					 DMA_STATUS_RPS | \
+					 DMA_STATUS_RU | \
+					 DMA_STATUS_RI | \
+					 DMA_STATUS_OVF | \
+					 DMA_STATUS_MSK_RX_COMMON)
+
+#define DMA_STATUS_MSK_TX		(DMA_STATUS_ETI | \
+					 DMA_STATUS_UNF | \
+					 DMA_STATUS_TJT | \
+					 DMA_STATUS_TU | \
+					 DMA_STATUS_TPS | \
+					 DMA_STATUS_TI | \
+					 DMA_STATUS_MSK_TX_COMMON)
+
+/* Following DMA defines are chanels oriented */
+#define DMA_CHAN_OFFSET			0x100
+
+static inline u32 dma_chan_base_addr(u32 base, u32 chan)
+{
+	return base + chan * DMA_CHAN_OFFSET;
+}
+
+#define DMA_CHAN_NEWFUNC_CONFIG(chan)	dma_chan_base_addr(DMA_NEWFUNC_CONFIG, chan)
+#define DMA_CHAN_XMT_POLL_DEMAND(chan)	dma_chan_base_addr(DMA_XMT_POLL_DEMAND, chan)
+#define DMA_CHAN_INTR_ENA(chan)		dma_chan_base_addr(DMA_INTR_ENA, chan)
+#define DMA_CHAN_CONTROL(chan)		dma_chan_base_addr(DMA_CONTROL, chan)
+#define DMA_CHAN_STATUS(chan)		dma_chan_base_addr(DMA_STATUS, chan)
+#define DMA_CHAN_BUS_MODE(chan)		dma_chan_base_addr(DMA_BUS_MODE, chan)
+#define DMA_CHAN_RCV_BASE_ADDR(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR, chan)
+#define DMA_CHAN_RCV_BASE_ADDR64(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR64, chan)
+#define DMA_CHAN_RCV_BASE_ADDR64_HI(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR64_HI, chan)
+#define DMA_CHAN_TX_BASE_ADDR(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR, chan)
+#define DMA_CHAN_TX_BASE_ADDR64(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR64, chan)
+#define DMA_CHAN_TX_BASE_ADDR64_HI(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR64_HI, chan)
+#define DMA_CHAN_RX_WATCHDOG(chan)	dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
+
+#define NUM_DWEGMAC_DMA_REGS	23
+
+#endif /* __DWEGMAC_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index c5768bbec38e..4674af3d78cb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -61,7 +61,7 @@ static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
 		dev_info(priv->device, "Enhanced/Alternate descriptors\n");
 
 		/* GMAC older than 3.50 has no extended descriptors */
-		if (priv->synopsys_id >= DWMAC_CORE_3_50) {
+		if (priv->synopsys_id >= DWMAC_CORE_3_50 || priv->plat->has_egmac) {
 			dev_info(priv->device, "Enabled extended descriptors\n");
 			priv->extend_desc = 1;
 		} else {
@@ -107,6 +107,7 @@ static const struct stmmac_hwif_entry {
 	bool gmac;
 	bool gmac4;
 	bool xgmac;
+	bool egmac;
 	u32 min_id;
 	u32 dev_id;
 	const struct stmmac_regs_off regs;
@@ -125,6 +126,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = false,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = 0,
 		.regs = {
 			.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -143,6 +145,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = true,
 		.gmac4 = false,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = 0,
 		.regs = {
 			.ptp_off = PTP_GMAC3_X_OFFSET,
@@ -161,6 +164,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = true,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = 0,
 		.regs = {
 			.ptp_off = PTP_GMAC4_OFFSET,
@@ -179,6 +183,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = true,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = DWMAC_CORE_4_00,
 		.regs = {
 			.ptp_off = PTP_GMAC4_OFFSET,
@@ -197,6 +202,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = true,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = DWMAC_CORE_4_10,
 		.regs = {
 			.ptp_off = PTP_GMAC4_OFFSET,
@@ -215,6 +221,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = true,
 		.xgmac = false,
+		.egmac = false,
 		.min_id = DWMAC_CORE_5_10,
 		.regs = {
 			.ptp_off = PTP_GMAC4_OFFSET,
@@ -233,6 +240,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = false,
 		.xgmac = true,
+		.egmac = false,
 		.min_id = DWXGMAC_CORE_2_10,
 		.dev_id = DWXGMAC_ID,
 		.regs = {
@@ -252,6 +260,7 @@ static const struct stmmac_hwif_entry {
 		.gmac = false,
 		.gmac4 = false,
 		.xgmac = true,
+		.egmac = false,
 		.min_id = DWXLGMAC_CORE_2_00,
 		.dev_id = DWXLGMAC_ID,
 		.regs = {
@@ -267,11 +276,50 @@ static const struct stmmac_hwif_entry {
 		.mmc = &dwxgmac_mmc_ops,
 		.setup = dwxlgmac2_setup,
 		.quirks = stmmac_dwxlgmac_quirks,
+	}, {
+		.gmac = false,
+		.gmac4 = false,
+		.xgmac = false,
+		.egmac = true,
+		.min_id = DWEGMAC_CORE_1_00,
+		.regs = {
+			.ptp_off = PTP_GMAC3_X_OFFSET,
+			.mmc_off = MMC_GMAC3_X_OFFSET,
+		},
+		.desc = NULL,
+		.dma = &dwegmac_dma_ops,
+		.mac = &dwegmac_ops,
+		.hwtimestamp = &stmmac_ptp,
+		.mode = NULL,
+		.tc = NULL,
+		.mmc = &dwmac_mmc_ops,
+		.setup = dwegmac_setup,
+		.quirks = stmmac_dwmac1_quirks,
+	}, {
+		.gmac = false,
+		.gmac4 = false,
+		.xgmac = false,
+		.egmac = true,
+		.min_id = DWMAC_CORE_3_50,
+		.regs = {
+			.ptp_off = PTP_GMAC3_X_OFFSET,
+			.mmc_off = MMC_GMAC3_X_OFFSET,
+		},
+		.desc = NULL,
+		.dma = &dwmac1000_dma_ops,
+		.mac = &dwmac1000_ops,
+		.hwtimestamp = &stmmac_ptp,
+		.mode = NULL,
+		.tc = NULL,
+		.mmc = &dwmac_mmc_ops,
+		.setup = dwmac1000_setup,
+		.quirks = stmmac_dwmac1_quirks,
 	},
 };
 
 int stmmac_hwif_init(struct stmmac_priv *priv)
 {
+	bool needs_egmac = priv->plat->has_egmac;
 	bool needs_xgmac = priv->plat->has_xgmac;
 	bool needs_gmac4 = priv->plat->has_gmac4;
 	bool needs_gmac = priv->plat->has_gmac;
@@ -281,7 +329,7 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
 	u32 id, dev_id = 0;
 	int i, ret;
 
-	if (needs_gmac) {
+	if (needs_gmac || needs_egmac) {
 		id = stmmac_get_id(priv, GMAC_VERSION);
 	} else if (needs_gmac4 || needs_xgmac) {
 		id = stmmac_get_id(priv, GMAC4_VERSION);
@@ -321,6 +369,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
 			continue;
 		if (needs_xgmac ^ entry->xgmac)
 			continue;
+		if (needs_egmac ^ entry->egmac)
+			continue;
 		/* Use synopsys_id var because some setups can override this */
 		if (priv->synopsys_id < entry->min_id)
 			continue;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 00be9a7003c8..41989903e8c9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -667,6 +667,8 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
 extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
 extern const struct stmmac_mmc_ops dwmac_mmc_ops;
 extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
+extern const struct stmmac_ops dwegmac_ops;
+extern const struct stmmac_dma_ops dwegmac_dma_ops;
 
 #define GMAC_VERSION		0x00000020	/* GMAC CORE Version */
 #define GMAC4_VERSION		0x00000110	/* GMAC4+ CORE Version */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 2ae73ab842d4..dba33ce392a8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -596,7 +596,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
 				priv->xstats.phy_eee_wakeup_error_n = val;
 		}
 
-		if (priv->synopsys_id >= DWMAC_CORE_3_50)
+		if (priv->synopsys_id >= DWMAC_CORE_3_50 || priv->plat->has_egmac)
 			stmmac_mac_debug(priv, priv->ioaddr,
 					(void *)&priv->xstats,
 					rx_queues_count, tx_queues_count);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index e8619853b6d6..f91dd3f69fef 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6936,7 +6936,8 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 	 * riwt_off field from the platform.
 	 */
 	if (((priv->synopsys_id >= DWMAC_CORE_3_50) ||
-	    (priv->plat->has_xgmac)) && (!priv->plat->riwt_off)) {
+	    (priv->plat->has_xgmac) || (priv->plat->has_egmac)) &&
+	    (!priv->plat->riwt_off)) {
 		priv->use_riwt = 1;
 		dev_info(priv->device,
 			 "Enable RX Mitigation via HW Watchdog Timer\n");
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 2fcd83f6db14..0e36259a9568 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -295,5 +295,6 @@ struct plat_stmmacenet_data {
 	bool serdes_up_after_phy_linkup;
 	const struct dwmac4_addrs *dwmac4_addrs;
 	bool has_integrated_pcs;
+	int has_egmac;
 };
 #endif
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 04/11] net: stmmac: Allow platforms to set irq_flags
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (2 preceding siblings ...)
  2023-08-22  9:40 ` [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 05/11] net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe() Feiyang Chen
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Some platforms need extra irq flags to request irq multi msi, add
irq_flags variable for them.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c    | 16 +++++++++-------
 include/linux/stmmac.h                           |  1 +
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f91dd3f69fef..1d67e5ec5fac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3515,7 +3515,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 	int_name = priv->int_name_mac;
 	sprintf(int_name, "%s:%s", dev->name, "mac");
 	ret = request_irq(dev->irq, stmmac_mac_interrupt,
-			  0, int_name, dev);
+			  priv->plat->irq_flags, int_name, dev);
 	if (unlikely(ret < 0)) {
 		netdev_err(priv->dev,
 			   "%s: alloc mac MSI %d (error: %d)\n",
@@ -3532,7 +3532,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s", dev->name, "wol");
 		ret = request_irq(priv->wol_irq,
 				  stmmac_mac_interrupt,
-				  0, int_name, dev);
+				  priv->plat->irq_flags, int_name, dev);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc wol MSI %d (error: %d)\n",
@@ -3550,7 +3550,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s", dev->name, "lpi");
 		ret = request_irq(priv->lpi_irq,
 				  stmmac_mac_interrupt,
-				  0, int_name, dev);
+				  priv->plat->irq_flags, int_name, dev);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc lpi MSI %d (error: %d)\n",
@@ -3568,7 +3568,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s", dev->name, "safety-ce");
 		ret = request_irq(priv->sfty_ce_irq,
 				  stmmac_safety_interrupt,
-				  0, int_name, dev);
+				  priv->plat->irq_flags, int_name, dev);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc sfty ce MSI %d (error: %d)\n",
@@ -3586,7 +3586,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s", dev->name, "safety-ue");
 		ret = request_irq(priv->sfty_ue_irq,
 				  stmmac_safety_interrupt,
-				  0, int_name, dev);
+				  priv->plat->irq_flags, int_name, dev);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc sfty ue MSI %d (error: %d)\n",
@@ -3607,7 +3607,8 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s-%d", dev->name, "rx", i);
 		ret = request_irq(priv->rx_irq[i],
 				  stmmac_msi_intr_rx,
-				  0, int_name, &priv->dma_conf.rx_queue[i]);
+				  priv->plat->irq_flags, int_name,
+				  &priv->dma_conf.rx_queue[i]);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc rx-%d  MSI %d (error: %d)\n",
@@ -3632,7 +3633,8 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
 		sprintf(int_name, "%s:%s-%d", dev->name, "tx", i);
 		ret = request_irq(priv->tx_irq[i],
 				  stmmac_msi_intr_tx,
-				  0, int_name, &priv->dma_conf.tx_queue[i]);
+				  priv->plat->irq_flags, int_name,
+				  &priv->dma_conf.tx_queue[i]);
 		if (unlikely(ret < 0)) {
 			netdev_err(priv->dev,
 				   "%s: alloc tx-%d  MSI %d (error: %d)\n",
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 0e36259a9568..75da4c7eb85c 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -296,5 +296,6 @@ struct plat_stmmacenet_data {
 	const struct dwmac4_addrs *dwmac4_addrs;
 	bool has_integrated_pcs;
 	int has_egmac;
+	u32 irq_flags;
 };
 #endif
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 05/11] net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe()
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (3 preceding siblings ...)
  2023-08-22  9:40 ` [PATCH v4 04/11] net: stmmac: Allow platforms to set irq_flags Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 06/11] net: stmmac: dwmac-loongson: Add LS7A support Feiyang Chen
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Add a setup() function to initialize data, and simplify code for
loongson_dwmac_probe().

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 89 +++++++++++--------
 1 file changed, 54 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index a25c187d3185..ff4fa74d2a11 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -9,7 +9,12 @@
 #include <linux/of_irq.h>
 #include "stmmac.h"
 
-static int loongson_default_data(struct plat_stmmacenet_data *plat)
+struct stmmac_pci_info {
+	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
+};
+
+static void loongson_default_data(struct pci_dev *pdev,
+				  struct plat_stmmacenet_data *plat)
 {
 	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
 	plat->has_gmac = 1;
@@ -34,23 +39,38 @@ static int loongson_default_data(struct plat_stmmacenet_data *plat)
 
 	/* Disable RX queues routing by default */
 	plat->rx_queues_cfg[0].pkt_route = 0x0;
+}
+
+static int loongson_gmac_data(struct pci_dev *pdev,
+			      struct plat_stmmacenet_data *plat)
+{
+	loongson_default_data(pdev, plat);
+
+	plat->multicast_filter_bins = 256;
+
+	plat->mdio_bus_data->phy_mask = 0;
 
-	/* Default to phy auto-detection */
 	plat->phy_addr = -1;
+	plat->phy_interface = PHY_INTERFACE_MODE_RGMII_ID;
 
 	plat->dma_cfg->pbl = 32;
 	plat->dma_cfg->pblx8 = true;
 
-	plat->multicast_filter_bins = 256;
 	return 0;
 }
 
-static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static struct stmmac_pci_info loongson_gmac_pci_info = {
+	.setup = loongson_gmac_data,
+};
+
+static int loongson_dwmac_probe(struct pci_dev *pdev,
+				const struct pci_device_id *id)
 {
+	int ret, i, bus_id, phy_mode;
 	struct plat_stmmacenet_data *plat;
+	struct stmmac_pci_info *info;
 	struct stmmac_resources res;
 	struct device_node *np;
-	int ret, i, phy_mode;
 
 	np = dev_of_node(&pdev->dev);
 
@@ -59,39 +79,32 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
 		return -ENODEV;
 	}
 
-	if (!of_device_is_compatible(np, "loongson, pci-gmac")) {
-		pr_info("dwmac_loongson_pci: Incompatible OF node\n");
-		return -ENODEV;
-	}
-
 	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
 	if (!plat)
 		return -ENOMEM;
 
+	plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+					   sizeof(*plat->mdio_bus_data),
+					   GFP_KERNEL);
+	if (!plat->mdio_bus_data)
+		return -ENOMEM;
+
+	plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
+				     GFP_KERNEL);
+	if (!plat->dma_cfg)
+		return -ENOMEM;
+
 	plat->mdio_node = of_get_child_by_name(np, "mdio");
 	if (plat->mdio_node) {
 		dev_info(&pdev->dev, "Found MDIO subnode\n");
-
-		plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
-						   sizeof(*plat->mdio_bus_data),
-						   GFP_KERNEL);
-		if (!plat->mdio_bus_data) {
-			ret = -ENOMEM;
-			goto err_put_node;
-		}
 		plat->mdio_bus_data->needs_reset = true;
 	}
 
-	plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL);
-	if (!plat->dma_cfg) {
-		ret = -ENOMEM;
-		goto err_put_node;
-	}
-
 	/* Enable pci device */
 	ret = pci_enable_device(pdev);
 	if (ret) {
-		dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__);
+		dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
+			__func__);
 		goto err_put_node;
 	}
 
@@ -105,9 +118,16 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
 		break;
 	}
 
-	plat->bus_id = of_alias_get_id(np, "ethernet");
-	if (plat->bus_id < 0)
-		plat->bus_id = pci_dev_id(pdev);
+	pci_set_master(pdev);
+
+	info = (struct stmmac_pci_info *)id->driver_data;
+	ret = info->setup(pdev, plat);
+	if (ret)
+		goto err_disable_device;
+
+	bus_id = of_alias_get_id(np, "ethernet");
+	if (bus_id >= 0)
+		plat->bus_id = bus_id;
 
 	phy_mode = device_get_phy_mode(&pdev->dev);
 	if (phy_mode < 0) {
@@ -115,14 +135,10 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
 		ret = phy_mode;
 		goto err_disable_device;
 	}
-
 	plat->phy_interface = phy_mode;
-	plat->interface = PHY_INTERFACE_MODE_GMII;
 
-	pci_set_master(pdev);
-
-	loongson_default_data(plat);
 	pci_enable_msi(pdev);
+
 	memset(&res, 0, sizeof(res));
 	res.addr = pcim_iomap_table(pdev)[0];
 
@@ -135,7 +151,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
 
 	res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
 	if (res.wol_irq < 0) {
-		dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n");
+		dev_info(&pdev->dev,
+			 "IRQ eth_wake_irq not found, using macirq\n");
 		res.wol_irq = res.irq;
 	}
 
@@ -219,8 +236,10 @@ static int __maybe_unused loongson_dwmac_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend,
 			 loongson_dwmac_resume);
 
+#define PCI_DEVICE_ID_LOONGSON_GMAC	0x7a03
+
 static const struct pci_device_id loongson_dwmac_id_table[] = {
-	{ PCI_VDEVICE(LOONGSON, 0x7a03) },
+	{ PCI_DEVICE_DATA(LOONGSON, GMAC, &loongson_gmac_pci_info) },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table);
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 06/11] net: stmmac: dwmac-loongson: Add LS7A support
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (4 preceding siblings ...)
  2023-08-22  9:40 ` [PATCH v4 05/11] net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe() Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22  9:40 ` [PATCH v4 07/11] net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support Feiyang Chen
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Current dwmac-loongson only support LS2K in the "probed with PCI
and configured with DT" manner. Add LS7A support on which the
devices are fully PCI (non-DT).

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 81 ++++++++++---------
 1 file changed, 44 insertions(+), 37 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index ff4fa74d2a11..dd7e9f262ca6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -16,8 +16,12 @@ struct stmmac_pci_info {
 static void loongson_default_data(struct pci_dev *pdev,
 				  struct plat_stmmacenet_data *plat)
 {
+	/* Get bus_id, this can be overloaded later */
+	plat->bus_id = (pci_domain_nr(pdev->bus) << 16) |
+		       PCI_DEVID(pdev->bus->number, pdev->devfn);
+
 	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
-	plat->has_gmac = 1;
+	plat->has_egmac = 1;
 	plat->force_sf_dma_mode = 1;
 
 	/* Set default value for multicast hash bins */
@@ -56,6 +60,9 @@ static int loongson_gmac_data(struct pci_dev *pdev,
 	plat->dma_cfg->pbl = 32;
 	plat->dma_cfg->pblx8 = true;
 
+	plat->clk_ref_rate = 125000000;
+	plat->clk_ptp_rate = 125000000;
+
 	return 0;
 }
 
@@ -72,13 +79,6 @@ static int loongson_dwmac_probe(struct pci_dev *pdev,
 	struct stmmac_resources res;
 	struct device_node *np;
 
-	np = dev_of_node(&pdev->dev);
-
-	if (!np) {
-		pr_info("dwmac_loongson_pci: No OF node\n");
-		return -ENODEV;
-	}
-
 	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
 	if (!plat)
 		return -ENOMEM;
@@ -94,6 +94,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev,
 	if (!plat->dma_cfg)
 		return -ENOMEM;
 
+	np = dev_of_node(&pdev->dev);
 	plat->mdio_node = of_get_child_by_name(np, "mdio");
 	if (plat->mdio_node) {
 		dev_info(&pdev->dev, "Found MDIO subnode\n");
@@ -125,42 +126,48 @@ static int loongson_dwmac_probe(struct pci_dev *pdev,
 	if (ret)
 		goto err_disable_device;
 
-	bus_id = of_alias_get_id(np, "ethernet");
-	if (bus_id >= 0)
-		plat->bus_id = bus_id;
+	if (np) {
+		bus_id = of_alias_get_id(np, "ethernet");
+		if (bus_id >= 0)
+			plat->bus_id = bus_id;
 
-	phy_mode = device_get_phy_mode(&pdev->dev);
-	if (phy_mode < 0) {
-		dev_err(&pdev->dev, "phy_mode not found\n");
-		ret = phy_mode;
-		goto err_disable_device;
+		phy_mode = device_get_phy_mode(&pdev->dev);
+		if (phy_mode < 0) {
+			dev_err(&pdev->dev, "phy_mode not found\n");
+			ret = phy_mode;
+			goto err_disable_device;
+		}
+		plat->phy_interface = phy_mode;
 	}
-	plat->phy_interface = phy_mode;
 
 	pci_enable_msi(pdev);
 
 	memset(&res, 0, sizeof(res));
 	res.addr = pcim_iomap_table(pdev)[0];
-
-	res.irq = of_irq_get_byname(np, "macirq");
-	if (res.irq < 0) {
-		dev_err(&pdev->dev, "IRQ macirq not found\n");
-		ret = -ENODEV;
-		goto err_disable_msi;
-	}
-
-	res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
-	if (res.wol_irq < 0) {
-		dev_info(&pdev->dev,
-			 "IRQ eth_wake_irq not found, using macirq\n");
-		res.wol_irq = res.irq;
-	}
-
-	res.lpi_irq = of_irq_get_byname(np, "eth_lpi");
-	if (res.lpi_irq < 0) {
-		dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
-		ret = -ENODEV;
-		goto err_disable_msi;
+	if (np) {
+		res.irq = of_irq_get_byname(np, "macirq");
+		if (res.irq < 0) {
+			dev_err(&pdev->dev, "IRQ macirq not found\n");
+			ret = -ENODEV;
+			goto err_disable_msi;
+		}
+
+		res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
+		if (res.wol_irq < 0) {
+			dev_info(&pdev->dev,
+				 "IRQ eth_wake_irq not found, using macirq\n");
+			res.wol_irq = res.irq;
+		}
+
+		res.lpi_irq = of_irq_get_byname(np, "eth_lpi");
+		if (res.lpi_irq < 0) {
+			dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
+			ret = -ENODEV;
+			goto err_disable_msi;
+		}
+	} else {
+		res.irq = pdev->irq;
+		res.wol_irq = pdev->irq;
 	}
 
 	ret = stmmac_dvr_probe(&pdev->dev, plat, &res);
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 07/11] net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (5 preceding siblings ...)
  2023-08-22  9:40 ` [PATCH v4 06/11] net: stmmac: dwmac-loongson: Add LS7A support Feiyang Chen
@ 2023-08-22  9:40 ` Feiyang Chen
  2023-08-22  9:41 ` [PATCH v4 08/11] net: stmmac: dwegmac: Fix channel numbers Feiyang Chen
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:40 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Set 64-Bit DMA and request allocation for MSI for specific versions.
Some features of Loongson platforms are bound to the GMAC_VERSION
register. We have to read its value in order to get the correct
channel number and DMA configuration.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 153 ++++++++++++++----
 1 file changed, 123 insertions(+), 30 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index dd7e9f262ca6..0748bafd3aec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -6,13 +6,108 @@
 #include <linux/pci.h>
 #include <linux/dmi.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 #include <linux/of_irq.h>
 #include "stmmac.h"
 
 struct stmmac_pci_info {
 	int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
+	int (*config)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat,
+		      struct stmmac_resources *res, struct device_node *np);
 };
 
+static void loongson_dwmac_config_dma64(struct plat_stmmacenet_data *plat)
+{
+	plat->host_dma_width = 64;
+	plat->dma_cfg->dma64 = true;
+}
+
+static u32 get_irq_type(struct device_node *np)
+{
+	struct of_phandle_args oirq;
+
+	if (np && of_irq_parse_one(np, 0, &oirq) == 0 && oirq.args_count == 2)
+		return oirq.args[1];
+
+	return IRQF_TRIGGER_RISING;
+}
+
+static int loongson_dwmac_config_single_irq(struct pci_dev *pdev,
+					    struct plat_stmmacenet_data *plat,
+					    struct stmmac_resources *res,
+					    struct device_node *np)
+{
+	if (np) {
+		res->irq = of_irq_get_byname(np, "macirq");
+		if (res->irq < 0) {
+			dev_err(&pdev->dev, "IRQ macirq not found\n");
+			return -ENODEV;
+		}
+
+		res->wol_irq = of_irq_get_byname(np, "eth_wake_irq");
+		if (res->wol_irq < 0) {
+			dev_info(&pdev->dev,
+				 "IRQ eth_wake_irq not found, using macirq\n");
+			res->wol_irq = res->irq;
+		}
+
+		res->lpi_irq = of_irq_get_byname(np, "eth_lpi");
+		if (res->lpi_irq < 0) {
+			dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
+			return -ENODEV;
+		}
+	} else {
+		res->irq = pdev->irq;
+		res->wol_irq = res->irq;
+	}
+
+	plat->multi_msi_en = 0;
+	dev_info(&pdev->dev, "%s: Single IRQ enablement successful\n",
+		 __func__);
+
+	return 0;
+}
+
+static int loongson_dwmac_config_multi_msi(struct pci_dev *pdev,
+					   struct plat_stmmacenet_data *plat,
+					   struct stmmac_resources *res,
+					   struct device_node *np,
+					   int channel_num)
+{
+	int i, ret, vecs;
+
+	vecs = roundup_pow_of_two(channel_num * 2 + 1);
+	ret = pci_alloc_irq_vectors(pdev, vecs, vecs, PCI_IRQ_MSI);
+	if (ret < 0) {
+		dev_info(&pdev->dev,
+			 "MSI enable failed, Fallback to legacy interrupt\n");
+		return loongson_dwmac_config_single_irq(pdev, plat, res, np);
+	}
+
+	plat->rx_queues_to_use = channel_num;
+	plat->tx_queues_to_use = channel_num;
+	plat->irq_flags = get_irq_type(np);
+
+	res->irq = pci_irq_vector(pdev, 0);
+	res->wol_irq = res->irq;
+
+	/* INT NAME | MAC | CH7 rx | CH7 tx | ... | CH0 rx | CH0 tx |
+	 * --------- ----- -------- --------  ...  -------- --------
+	 * IRQ NUM  |  0  |   1    |   2    | ... |   15   |   16   |
+	 */
+	for (i = 0; i < channel_num; i++) {
+		res->rx_irq[channel_num - 1 - i] =
+			pci_irq_vector(pdev, 1 + i * 2);
+		res->tx_irq[channel_num - 1 - i] =
+			pci_irq_vector(pdev, 2 + i * 2);
+	}
+
+	plat->multi_msi_en = 1;
+	dev_info(&pdev->dev, "%s: multi MSI enablement successful\n", __func__);
+
+	return 0;
+}
+
 static void loongson_default_data(struct pci_dev *pdev,
 				  struct plat_stmmacenet_data *plat)
 {
@@ -66,8 +161,32 @@ static int loongson_gmac_data(struct pci_dev *pdev,
 	return 0;
 }
 
+static int loongson_gmac_config(struct pci_dev *pdev,
+				struct plat_stmmacenet_data *plat,
+				struct stmmac_resources *res,
+				struct device_node *np)
+{
+	int ret;
+	u32 version = readl(res->addr + GMAC_VERSION);
+
+	if (version & 0x00008000)
+		loongson_dwmac_config_dma64(plat);
+
+	switch (version & 0xff) {
+	case DWEGMAC_CORE_1_00:
+		ret = loongson_dwmac_config_multi_msi(pdev, plat, res, np, 8);
+		break;
+	default:
+		ret = loongson_dwmac_config_single_irq(pdev, plat, res, np);
+		break;
+	}
+
+	return ret;
+}
+
 static struct stmmac_pci_info loongson_gmac_pci_info = {
 	.setup = loongson_gmac_data,
+	.config = loongson_gmac_config,
 };
 
 static int loongson_dwmac_probe(struct pci_dev *pdev,
@@ -140,44 +259,19 @@ static int loongson_dwmac_probe(struct pci_dev *pdev,
 		plat->phy_interface = phy_mode;
 	}
 
-	pci_enable_msi(pdev);
-
 	memset(&res, 0, sizeof(res));
 	res.addr = pcim_iomap_table(pdev)[0];
-	if (np) {
-		res.irq = of_irq_get_byname(np, "macirq");
-		if (res.irq < 0) {
-			dev_err(&pdev->dev, "IRQ macirq not found\n");
-			ret = -ENODEV;
-			goto err_disable_msi;
-		}
-
-		res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
-		if (res.wol_irq < 0) {
-			dev_info(&pdev->dev,
-				 "IRQ eth_wake_irq not found, using macirq\n");
-			res.wol_irq = res.irq;
-		}
 
-		res.lpi_irq = of_irq_get_byname(np, "eth_lpi");
-		if (res.lpi_irq < 0) {
-			dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
-			ret = -ENODEV;
-			goto err_disable_msi;
-		}
-	} else {
-		res.irq = pdev->irq;
-		res.wol_irq = pdev->irq;
-	}
+	ret = info->config(pdev, plat, &res, np);
+	if (ret)
+		goto err_disable_device;
 
 	ret = stmmac_dvr_probe(&pdev->dev, plat, &res);
 	if (ret)
-		goto err_disable_msi;
+		goto err_disable_device;
 
 	return ret;
 
-err_disable_msi:
-	pci_disable_msi(pdev);
 err_disable_device:
 	pci_disable_device(pdev);
 err_put_node:
@@ -201,7 +295,6 @@ static void loongson_dwmac_remove(struct pci_dev *pdev)
 		break;
 	}
 
-	pci_disable_msi(pdev);
 	pci_disable_device(pdev);
 }
 
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 08/11] net: stmmac: dwegmac: Fix channel numbers
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (6 preceding siblings ...)
  2023-08-22  9:40 ` [PATCH v4 07/11] net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support Feiyang Chen
@ 2023-08-22  9:41 ` Feiyang Chen
  2023-08-22  9:41 ` [PATCH v4 09/11] net: stmmac: dwmac-loongson: Disable flow control for GMAC Feiyang Chen
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:41 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Some Loongson platforms cannot obtain the TX and RX number of channels.
Add the dwegmac_flag for them and specify the number of channels.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c    | 10 ++++++++--
 drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c |  1 +
 include/linux/stmmac.h                               |  5 +++++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
index 9bb0564fbeff..157f0e3687be 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
@@ -479,8 +479,14 @@ static int dwegmac_get_hw_feature(struct stmmac_priv *priv,
 	dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
 	dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
 	/* TX and RX number of channels */
-	dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
-	dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+	if (FIELD_GET(DWEGMAC_FIX_CHANNEL_NUM, priv->plat->dwegmac_flags) &&
+	    ((hw_cap & (DMA_HW_FEAT_RXCHCNT | DMA_HW_FEAT_TXCHCNT)) >> 20) == 0) {
+		dma_cap->number_rx_channel = 8;
+		dma_cap->number_tx_channel = 8;
+	} else {
+		dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+		dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+	}
 	/* Alternate (enhanced) DESC mode */
 	dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index 0748bafd3aec..9fb27fc94d2a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -175,6 +175,7 @@ static int loongson_gmac_config(struct pci_dev *pdev,
 	switch (version & 0xff) {
 	case DWEGMAC_CORE_1_00:
 		ret = loongson_dwmac_config_multi_msi(pdev, plat, res, np, 8);
+		plat->dwegmac_flags |= FIELD_PREP(DWEGMAC_FIX_CHANNEL_NUM, 1);
 		break;
 	default:
 		ret = loongson_dwmac_config_single_irq(pdev, plat, res, np);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 75da4c7eb85c..e4088d2a0f39 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -14,6 +14,8 @@
 
 #include <linux/platform_device.h>
 #include <linux/phy.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
 
 #define MTL_MAX_RX_QUEUES	8
 #define MTL_MAX_TX_QUEUES	8
@@ -205,6 +207,8 @@ struct dwmac4_addrs {
 	u32 mtl_low_cred_offset;
 };
 
+#define DWEGMAC_FIX_CHANNEL_NUM		BIT(0)
+
 struct plat_stmmacenet_data {
 	int bus_id;
 	int phy_addr;
@@ -297,5 +301,6 @@ struct plat_stmmacenet_data {
 	bool has_integrated_pcs;
 	int has_egmac;
 	u32 irq_flags;
+	unsigned int dwegmac_flags;
 };
 #endif
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 09/11] net: stmmac: dwmac-loongson: Disable flow control for GMAC
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (7 preceding siblings ...)
  2023-08-22  9:41 ` [PATCH v4 08/11] net: stmmac: dwegmac: Fix channel numbers Feiyang Chen
@ 2023-08-22  9:41 ` Feiyang Chen
  2023-08-22  9:41 ` [PATCH v4 10/11] net: stmmac: dwegmac: Disable coe Feiyang Chen
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:41 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Loongson GMAC does not support Flow Control feature. Set dwmac_flag
to disable it.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 2 ++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c    | 6 ++++--
 include/linux/stmmac.h                               | 1 +
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index 9fb27fc94d2a..1f466b1e80d9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -182,6 +182,8 @@ static int loongson_gmac_config(struct pci_dev *pdev,
 		break;
 	}
 
+	plat->dwegmac_flags |= FIELD_PREP(DWEGMAC_DISABLE_FLOW_CONTROL, 1);
+
 	return ret;
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1d67e5ec5fac..a98bcd797720 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1213,8 +1213,10 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
 		xpcs_get_interfaces(priv->hw->xpcs,
 				    priv->phylink_config.supported_interfaces);
 
-	priv->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
-		MAC_10 | MAC_100;
+	priv->phylink_config.mac_capabilities = MAC_10 | MAC_100;
+	if (!FIELD_GET(DWEGMAC_DISABLE_FLOW_CONTROL, priv->plat->dwegmac_flags))
+		priv->phylink_config.mac_capabilities |=
+			MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
 
 	if (!max_speed || max_speed >= 1000)
 		priv->phylink_config.mac_capabilities |= MAC_1000;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index e4088d2a0f39..e97774efd451 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -208,6 +208,7 @@ struct dwmac4_addrs {
 };
 
 #define DWEGMAC_FIX_CHANNEL_NUM		BIT(0)
+#define DWEGMAC_DISABLE_FLOW_CONTROL	BIT(1)
 
 struct plat_stmmacenet_data {
 	int bus_id;
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 10/11] net: stmmac: dwegmac: Disable coe
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (8 preceding siblings ...)
  2023-08-22  9:41 ` [PATCH v4 09/11] net: stmmac: dwmac-loongson: Disable flow control for GMAC Feiyang Chen
@ 2023-08-22  9:41 ` Feiyang Chen
  2023-08-22  9:41 ` [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support Feiyang Chen
  2023-08-24  1:47 ` [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:41 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Some Loongson Platforms do not support coe, so disable them.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 drivers/net/ethernet/stmicro/stmmac/hwif.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 4674af3d78cb..b535d63c4993 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -74,6 +74,11 @@ static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
 		mac->desc = &ndesc_ops;
 	}
 
+	if (priv->plat->has_egmac && priv->synopsys_id == DWEGMAC_CORE_1_00) {
+		priv->plat->rx_coe = STMMAC_RX_COE_NONE;
+		priv->plat->tx_coe = 0;
+	}
+
 	stmmac_dwmac_mode_quirk(priv);
 	return 0;
 }
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (9 preceding siblings ...)
  2023-08-22  9:41 ` [PATCH v4 10/11] net: stmmac: dwegmac: Disable coe Feiyang Chen
@ 2023-08-22  9:41 ` Feiyang Chen
  2023-08-22 11:45   ` Russell King (Oracle)
  2023-08-24  1:47 ` [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
  11 siblings, 1 reply; 16+ messages in thread
From: Feiyang Chen @ 2023-08-22  9:41 UTC (permalink / raw)
  To: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai
  Cc: Feiyang Chen, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch, chris.chenfeiyang

Add GNET support. Current GNET does not support half duplex mode.
GNET on LS7A only supports ANE when speed is set to 1000M.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
---
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 82 +++++++++++++++++++
 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |  6 ++
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  3 +-
 include/linux/stmmac.h                        |  2 +
 4 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index 1f466b1e80d9..7b08c54f6c62 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -192,6 +192,86 @@ static struct stmmac_pci_info loongson_gmac_pci_info = {
 	.config = loongson_gmac_config,
 };
 
+static void loongson_gnet_fix_speed(void *priv, unsigned int speed)
+{
+	struct net_device *ndev = dev_get_drvdata(priv);
+	struct stmmac_priv *ptr = netdev_priv(ndev);
+
+	/* The controller and PHY don't work well together.
+	 * We need to use the PS bit to check if the controller's status
+	 * is correct and reset PHY if necessary.
+	 */
+	if (speed == SPEED_1000)
+		if (readl(ptr->ioaddr + MAC_CTRL_REG) & (1 << 15) /* PS */)
+			phy_restart_aneg(ndev->phydev);
+}
+
+static int loongson_gnet_data(struct pci_dev *pdev,
+			      struct plat_stmmacenet_data *plat)
+{
+	loongson_default_data(pdev, plat);
+
+	plat->multicast_filter_bins = 256;
+
+	plat->mdio_bus_data->phy_mask = 0xfffffffb;
+
+	plat->phy_addr = 2;
+	plat->phy_interface = PHY_INTERFACE_MODE_INTERNAL;
+
+	plat->bsp_priv = &pdev->dev;
+	plat->fix_mac_speed = loongson_gnet_fix_speed;
+
+	plat->dma_cfg->pbl = 32;
+	plat->dma_cfg->pblx8 = true;
+
+	plat->clk_ref_rate = 125000000;
+	plat->clk_ptp_rate = 125000000;
+
+	return 0;
+}
+
+static int loongson_gnet_config(struct pci_dev *pdev,
+				struct plat_stmmacenet_data *plat,
+				struct stmmac_resources *res,
+				struct device_node *np)
+{
+	int ret;
+	u32 version = readl(res->addr + GMAC_VERSION);
+
+	if (version & 0x00008000)
+		loongson_dwmac_config_dma64(plat);
+
+	switch (version & 0xff) {
+	case DWEGMAC_CORE_1_00:
+		ret = loongson_dwmac_config_multi_msi(pdev, plat, res, np, 8);
+		break;
+	default:
+		ret = loongson_dwmac_config_single_irq(pdev, plat, res, np);
+		break;
+	}
+
+	switch (pdev->revision) {
+	case 0x00:
+		plat->dwegmac_flags |=
+			FIELD_PREP(DWEGMAC_DISABLE_HALF_DUPLEX, 1) |
+			FIELD_PREP(DWEGMAC_DISABLE_FORCE_1000, 1);
+		break;
+	case 0x01:
+		plat->dwegmac_flags |=
+			FIELD_PREP(DWEGMAC_DISABLE_HALF_DUPLEX, 1);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct stmmac_pci_info loongson_gnet_pci_info = {
+	.setup = loongson_gnet_data,
+	.config = loongson_gnet_config,
+};
+
 static int loongson_dwmac_probe(struct pci_dev *pdev,
 				const struct pci_device_id *id)
 {
@@ -340,9 +420,11 @@ static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend,
 			 loongson_dwmac_resume);
 
 #define PCI_DEVICE_ID_LOONGSON_GMAC	0x7a03
+#define PCI_DEVICE_ID_LOONGSON_GNET	0x7a13
 
 static const struct pci_device_id loongson_dwmac_id_table[] = {
 	{ PCI_DEVICE_DATA(LOONGSON, GMAC, &loongson_gmac_pci_info) },
+	{ PCI_DEVICE_DATA(LOONGSON, GNET, &loongson_gnet_pci_info) },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index dba33ce392a8..0006a0b2754b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -404,6 +404,12 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
 		return 0;
 	}
 
+	if (FIELD_GET(DWEGMAC_DISABLE_FORCE_1000, priv->plat->dwegmac_flags)) {
+		if (cmd->base.speed == SPEED_1000 &&
+		    cmd->base.autoneg != AUTONEG_ENABLE)
+			return -EOPNOTSUPP;
+	}
+
 	return phylink_ethtool_ksettings_set(priv->phylink, cmd);
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a98bcd797720..fa4d7b90c5fa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1242,7 +1242,8 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
 	}
 
 	/* Half-Duplex can only work with single queue */
-	if (priv->plat->tx_queues_to_use > 1)
+	if (priv->plat->tx_queues_to_use > 1 ||
+	    FIELD_GET(DWEGMAC_DISABLE_HALF_DUPLEX, priv->plat->dwegmac_flags))
 		priv->phylink_config.mac_capabilities &=
 			~(MAC_10HD | MAC_100HD | MAC_1000HD);
 	priv->phylink_config.mac_managed_pm = true;
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index e97774efd451..d369993a5d9d 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -209,6 +209,8 @@ struct dwmac4_addrs {
 
 #define DWEGMAC_FIX_CHANNEL_NUM		BIT(0)
 #define DWEGMAC_DISABLE_FLOW_CONTROL	BIT(1)
+#define DWEGMAC_DISABLE_HALF_DUPLEX	BIT(2)
+#define DWEGMAC_DISABLE_FORCE_1000	BIT(3)
 
 struct plat_stmmacenet_data {
 	int bus_id;
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks
  2023-08-22  9:40 ` [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks Feiyang Chen
@ 2023-08-22 10:03   ` Russell King (Oracle)
  0 siblings, 0 replies; 16+ messages in thread
From: Russell King (Oracle) @ 2023-08-22 10:03 UTC (permalink / raw)
  To: Feiyang Chen
  Cc: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai, dongbiao, guyinggang, siyanteng, loongson-kernel,
	netdev, loongarch, chris.chenfeiyang

On Tue, Aug 22, 2023 at 05:40:26PM +0800, Feiyang Chen wrote:
> @@ -636,7 +637,8 @@ static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable)
>   * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST
>   * If addr is NULL, clear the slot
>   */
> -static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw,
> +static void sun8i_dwmac_set_umac_addr(struct stmmac_priv *priv,
> +				      struct mac_device_info *hw,
>  				      const unsigned char *addr,
>  				      unsigned int reg_n)
>  {

Given that hw is always priv->hw, would it be sensible to simplify the
callback by dropping the "hw" argument, and have the called methods do:

	struct mac_device_info *hw = priv->hw;

> @@ -657,7 +659,8 @@ static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw,
>  	}
>  }
>  
> -static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw,
> +static void sun8i_dwmac_get_umac_addr(struct stmmac_priv *priv,
> +				      struct mac_device_info *hw,
>  				      unsigned char *addr,
>  				      unsigned int reg_n)
>  {

Same here.

> @@ -680,7 +683,8 @@ static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw)
>  	return 1;
>  }
>  
> -static void sun8i_dwmac_set_filter(struct mac_device_info *hw,
> +static void sun8i_dwmac_set_filter(struct stmmac_priv *priv,
> +				   struct mac_device_info *hw,
>  				   struct net_device *dev)
>  {

Probably also worth doing for this method as well. I think the only
thing which this function uses is hw->unicast_filter_entries, so
one could declare:

	unsigned int unicast_filter_entries = priv->hw->unicast_filter_entries;

rather than carrying the pointer to both "priv" and "hw" through this
function.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support
  2023-08-22  9:41 ` [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support Feiyang Chen
@ 2023-08-22 11:45   ` Russell King (Oracle)
  0 siblings, 0 replies; 16+ messages in thread
From: Russell King (Oracle) @ 2023-08-22 11:45 UTC (permalink / raw)
  To: Feiyang Chen
  Cc: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai, dongbiao, guyinggang, siyanteng, loongson-kernel,
	netdev, loongarch, chris.chenfeiyang

On Tue, Aug 22, 2023 at 05:41:19PM +0800, Feiyang Chen wrote:
> @@ -192,6 +192,86 @@ static struct stmmac_pci_info loongson_gmac_pci_info = {
>  	.config = loongson_gmac_config,
>  };
>  
> +static void loongson_gnet_fix_speed(void *priv, unsigned int speed)
> +{

What tree are these patches against? They don't look like the net-next
tree, since net-next has changed the prototype for the fix_mac_speed
method. Also, it would be good for it to be called
"loongson_gnet_fix_mac_speed" so that grepping for "fix_mac_speed"
finds not only the callsite but also the method definitions too.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index a98bcd797720..fa4d7b90c5fa 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -1242,7 +1242,8 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
>  	}
>  
>  	/* Half-Duplex can only work with single queue */
> -	if (priv->plat->tx_queues_to_use > 1)
> +	if (priv->plat->tx_queues_to_use > 1 ||
> +	    FIELD_GET(DWEGMAC_DISABLE_HALF_DUPLEX, priv->plat->dwegmac_flags))
>  		priv->phylink_config.mac_capabilities &=
>  			~(MAC_10HD | MAC_100HD | MAC_1000HD);

There have been a number of shortcomings of stmmac's setup of the
phylink MAC capabilities recently, and I think it's getting to the
point where we need someone to bite the bullet and do something
about it.

Constantly extending conditions such as the above doesn't make a
lot of sense.

In patch 9, you've added:

+       priv->phylink_config.mac_capabilities = MAC_10 | MAC_100;
+       if (!FIELD_GET(DWEGMAC_DISABLE_FLOW_CONTROL, priv->plat->dwegmac_flags))
+               priv->phylink_config.mac_capabilities |=
+                       MAC_ASYM_PAUSE | MAC_SYM_PAUSE;

The only two capabilities that are unconditional are MAC_10FD and
MAC_100FD. Everything else is conditional on something.

I'm thinking two things:

1) the stmmac platform implementations should be responsible for
   initialising priv->phylink_config.mac_capabilities

2) phylink may need a function:
   phylink_set_max_speed(struct phylink_config *config, u32 max_speed);
   which does similar to phy_set_max_speed(), but operates on
   mac_capabilities. This can then be used after calling the platform
   setup of priv->phylink_config.mac_capabilities to limit the
   speed. I'm not entirely sure that this is required though. I don't
   think it's required for dwmac-intel, but would possibly be needed
   for stmmac_platform since there's a "max-speed" property in DT.

What I'm basically saying is... let's not make the setup of
mac_capabilities any more convoluted than it already is by adding
new flags which only exist to set or clear other bits.

Also, let's try to stick to positive logic where possible!

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms
  2023-08-22  9:40 ` [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms Feiyang Chen
@ 2023-08-22 16:13   ` Serge Semin
  0 siblings, 0 replies; 16+ messages in thread
From: Serge Semin @ 2023-08-22 16:13 UTC (permalink / raw)
  To: Feiyang Chen, andrew, Russell King
  Cc: hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai, dongbiao, guyinggang, siyanteng, loongson-kernel,
	netdev, loongarch, chris.chenfeiyang

On Tue, Aug 22, 2023 at 05:40:28PM +0800, Feiyang Chen wrote:
> Loongson platforms use an extended GMAC which supports 64-bit DMA
> and multi-channel.
> 
> There are two kinds of Loongson platforms. The first kind shares
> the same registers and has similar logic with dwmac1000. The second
> kind uses different registers and has more features.
> 
> Add extended GMAC support and then add two HWIF entries for Loongson
> platforms.

Holy mother! No, no, no! Don't ever do that! Here is what I see:

drivers/net/ethernet/stmicro/stmmac/dwegmac.h = drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c = drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c = drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +
                                                    drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +
                                                    DMA channel-specific settings +
                                                    useless OSR64 update.
drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h = drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +
                                                    64-bit address CSRs +
                                                    useless OSR64 update +
                                                    DMA channel-specific settings.

So you just copied the files from the generic DW GMAC MAC/DMA
implementations, altered a few lines there and renamed it to some
imaginary DW Extended GMAC. This is a nightmare to review and a
dead-end to maintain. Just NO! Here are the notes regarding your
device:

1. There is no DW Extended GMAC. The latest DW GMAC IP-core is of
v3.73a version. It supports various PHY interfaces and can work with
up to 1Gbps Full-duplex speed.

2. Generic DW GMAC 3.73a IP-core can be synthesised with multiple DMA
channels support. Such capability is enabled together with the AV
feature (Audio/Video feature). There can be up to 2 additional DMA
channels enabled. The higher DMA-channels-specific CSRs are available
with the 0x100 offset with respect to each other and the Channel 0
base address. Based on what is depicted on the Top-Level Block Diagram
of AV Support each DMA-channel is equipped with the MTL Tx/Rx FIFO
controller. So basically it's a fixed DMA/MTL-queue setup despite of
the DW QoS Eth and DW xGMACs which provide a way to map the MTL-queues
to DMA-channels at runtime.

BTW Based on the v3.73 IP-core Release notes the AV feature and thus the
multi-DMA-channels support was added in the IP-core v3.61a and since
then the product with such feature enabled is called as DWC Ethernet
QoS. It's mainly compatible with the standard DWC GMAC (DW Ether MAC
10/100/1000 controller) except the DMA-channels and the AV feature
setups. And it's absolutely different from what it currently called
DW Eth QoS v4.x/v5.x.

3. I failed to find anything about the 64-bit DMA-descriptors address
in the v3.73a IP-core databook. So most likely it's indeed either your
controller specific feature or a feature implemented by Synopsys for
the Loongson vendor but hasn't been released yet. In anyway AFAICS
this capability completely blocks the Chained descriptors
configuration and seeing it implies the (R|T)DES(6|7) fields
utilization the Timestamping will be unavailable too. So your
chain_mode.c fixes just convert the chain_mode.c file to implementing
the ring mode.

That's it. Your "Extended" GMAC isn't that special after all: just 8
DMA channels instead of 2, most likely AV-feature available and the
DMA-descriptors supporting 64-bit addresses. Even the MAC and DMA CSRs
space is almost the same as can be found in the generic DW GMAC.

What you should have done:
1. Update the dwmac1000_dma.c to support the multi-DMA-channels
controller setup.
2. Update ring_mode.c to support the 64-bit DMA-descriptor addresses.
3. Prevent the chain-mode from being enabled for your controller.

That's it AFAICS for now. But it's definitely no to what is currently
implemented.

-Serge(y)

> 
> Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn>
> ---
>  drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
>  drivers/net/ethernet/stmicro/stmmac/common.h  |   2 +
>  drivers/net/ethernet/stmicro/stmmac/dwegmac.h | 332 +++++++++++
>  .../ethernet/stmicro/stmmac/dwegmac_core.c    | 552 ++++++++++++++++++
>  .../net/ethernet/stmicro/stmmac/dwegmac_dma.c | 516 ++++++++++++++++
>  .../net/ethernet/stmicro/stmmac/dwegmac_dma.h | 190 ++++++
>  drivers/net/ethernet/stmicro/stmmac/hwif.c    |  54 +-
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |   2 +
>  .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |   2 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c |   3 +-
>  include/linux/stmmac.h                        |   1 +
>  11 files changed, 1651 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac.h
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index 10f32ded2bd9..1238cd736910 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
>  	      mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o	\
>  	      dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
>  	      stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
> -	      stmmac_xdp.o ring_mode64.o \
> +	      stmmac_xdp.o ring_mode64.o dwegmac_core.o dwegmac_dma.o \
>  	      $(stmmac-y)
>  
>  stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index 90a7784f71cb..74528a16b93a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -36,6 +36,7 @@
>  #define DWMAC_CORE_5_20		0x52
>  #define DWXGMAC_CORE_2_10	0x21
>  #define DWXLGMAC_CORE_2_00	0x20
> +#define DWEGMAC_CORE_1_00	0x10
>  
>  /* Device ID */
>  #define DWXGMAC_ID		0x76
> @@ -547,6 +548,7 @@ int dwmac1000_setup(struct stmmac_priv *priv);
>  int dwmac4_setup(struct stmmac_priv *priv);
>  int dwxgmac2_setup(struct stmmac_priv *priv);
>  int dwxlgmac2_setup(struct stmmac_priv *priv);
> +int dwegmac_setup(struct stmmac_priv *priv);
>  
>  void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
>  			 unsigned int high, unsigned int low);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac.h b/drivers/net/ethernet/stmicro/stmmac/dwegmac.h
> new file mode 100644
> index 000000000000..6f8fcf3ed409
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac.h
> @@ -0,0 +1,332 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __DWEGMAC_H__
> +#define __DWEGMAC_H__
> +
> +#include <linux/phy.h>
> +#include "common.h"
> +
> +#define GMAC_CONTROL			0x00000000	/* Configuration */
> +#define GMAC_FRAME_FILTER		0x00000004	/* Frame Filter */
> +#define GMAC_HASH_HIGH			0x00000008	/* Multicast Hash Table High */
> +#define GMAC_HASH_LOW			0x0000000c	/* Multicast Hash Table Low */
> +#define GMAC_MII_ADDR			0x00000010	/* MII Address */
> +#define GMAC_MII_DATA			0x00000014	/* MII Data */
> +#define GMAC_FLOW_CTRL			0x00000018	/* Flow Control */
> +#define GMAC_VLAN_TAG			0x0000001c	/* VLAN Tag */
> +#define GMAC_DEBUG			0x00000024	/* GMAC debug register */
> +#define GMAC_WAKEUP_FILTER		0x00000028	/* Wake-up Frame Filter */
> +
> +#define GMAC_INT_STATUS			0x00000038	/* interrupt status register */
> +#define GMAC_INT_STATUS_PMT		BIT(3)
> +#define GMAC_INT_STATUS_MMCIS		BIT(4)
> +#define GMAC_INT_STATUS_MMCRIS		BIT(5)
> +#define GMAC_INT_STATUS_MMCTIS		BIT(6)
> +#define GMAC_INT_STATUS_MMCCSUM		BIT(7)
> +#define GMAC_INT_STATUS_TSTAMP		BIT(9)
> +#define GMAC_INT_STATUS_LPIIS		BIT(10)
> +
> +/* interrupt mask register */
> +#define	GMAC_INT_MASK			0x0000003c
> +#define	GMAC_INT_DISABLE_RGMII		BIT(0)
> +#define	GMAC_INT_DISABLE_PCSLINK	BIT(1)
> +#define	GMAC_INT_DISABLE_PCSAN		BIT(2)
> +#define	GMAC_INT_DISABLE_PMT		BIT(3)
> +#define	GMAC_INT_DISABLE_TIMESTAMP	BIT(9)
> +#define	GMAC_INT_DISABLE_PCS		(GMAC_INT_DISABLE_RGMII | \
> +					 GMAC_INT_DISABLE_PCSLINK | \
> +					 GMAC_INT_DISABLE_PCSAN)
> +#define	GMAC_INT_DEFAULT_MASK		(GMAC_INT_DISABLE_TIMESTAMP | \
> +					 GMAC_INT_DISABLE_PCS)
> +
> +/* PMT Control and Status */
> +#define GMAC_PMT			0x0000002c
> +enum power_event {
> +	pointer_reset = 0x80000000,
> +	global_unicast = 0x00000200,
> +	wake_up_rx_frame = 0x00000040,
> +	magic_frame = 0x00000020,
> +	wake_up_frame_en = 0x00000004,
> +	magic_pkt_en = 0x00000002,
> +	power_down = 0x00000001,
> +};
> +
> +/* Energy Efficient Ethernet (EEE)
> + *
> + * LPI status, timer and control register offset
> + */
> +#define LPI_CTRL_STATUS			0x0030
> +#define LPI_TIMER_CTRL			0x0034
> +
> +/* LPI control and status defines */
> +#define LPI_CTRL_STATUS_LPITXA		0x00080000	/* Enable LPI TX Automate */
> +#define LPI_CTRL_STATUS_PLSEN		0x00040000	/* Enable PHY Link Status */
> +#define LPI_CTRL_STATUS_PLS		0x00020000	/* PHY Link Status */
> +#define LPI_CTRL_STATUS_LPIEN		0x00010000	/* LPI Enable */
> +#define LPI_CTRL_STATUS_RLPIST		0x00000200	/* Receive LPI state */
> +#define LPI_CTRL_STATUS_TLPIST		0x00000100	/* Transmit LPI state */
> +#define LPI_CTRL_STATUS_RLPIEX		0x00000008	/* Receive LPI Exit */
> +#define LPI_CTRL_STATUS_RLPIEN		0x00000004	/* Receive LPI Entry */
> +#define LPI_CTRL_STATUS_TLPIEX		0x00000002	/* Transmit LPI Exit */
> +#define LPI_CTRL_STATUS_TLPIEN		0x00000001	/* Transmit LPI Entry */
> +
> +/* GMAC HW ADDR regs */
> +#define GMAC_ADDR_HIGH(reg)		((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
> +					 0x00000040 + (reg * 8))
> +#define GMAC_ADDR_LOW(reg)		((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
> +					 0x00000044 + (reg * 8))
> +#define GMAC_MAX_PERFECT_ADDRESSES	1
> +
> +#define GMAC_PCS_BASE			0x000000c0	/* PCS register base */
> +#define GMAC_RGSMIIIS			0x000000d8	/* RGMII/SMII status */
> +
> +/* SGMII/RGMII status register */
> +#define GMAC_RGSMIIIS_LNKMODE		BIT(0)
> +#define GMAC_RGSMIIIS_SPEED		GENMASK(2, 1)
> +#define GMAC_RGSMIIIS_SPEED_SHIFT	1
> +#define GMAC_RGSMIIIS_LNKSTS		BIT(3)
> +#define GMAC_RGSMIIIS_JABTO		BIT(4)
> +#define GMAC_RGSMIIIS_FALSECARDET	BIT(5)
> +#define GMAC_RGSMIIIS_SMIDRXS		BIT(16)
> +/* LNKMOD */
> +#define GMAC_RGSMIIIS_LNKMOD_MASK	0x1
> +/* LNKSPEED */
> +#define GMAC_RGSMIIIS_SPEED_125		0x2
> +#define GMAC_RGSMIIIS_SPEED_25		0x1
> +#define GMAC_RGSMIIIS_SPEED_2_5		0x0
> +
> +/* GMAC Configuration defines */
> +#define GMAC_CONTROL_2K			0x08000000	/* IEEE 802.3as 2K packets */
> +#define GMAC_CONTROL_TC			0x01000000	/* Transmit Conf. in RGMII/SGMII */
> +#define GMAC_CONTROL_WD			0x00800000	/* Disable Watchdog on receive */
> +#define GMAC_CONTROL_JD			0x00400000	/* Jabber disable */
> +#define GMAC_CONTROL_BE			0x00200000	/* Frame Burst Enable */
> +#define GMAC_CONTROL_JE			0x00100000	/* Jumbo frame */
> +enum inter_frame_gap {
> +	GMAC_CONTROL_IFG_88 = 0x00040000,
> +	GMAC_CONTROL_IFG_80 = 0x00020000,
> +	GMAC_CONTROL_IFG_40 = 0x000e0000,
> +};
> +#define GMAC_CONTROL_DCRS		0x00010000	/* Disable carrier sense */
> +#define GMAC_CONTROL_PS			0x00008000	/* Port Select 0:GMI 1:MII */
> +#define GMAC_CONTROL_FES		0x00004000	/* Speed 0:10 1:100 */
> +#define GMAC_CONTROL_DO			0x00002000	/* Disable Rx Own */
> +#define GMAC_CONTROL_LM			0x00001000	/* Loop-back mode */
> +#define GMAC_CONTROL_DM			0x00000800	/* Duplex Mode */
> +#define GMAC_CONTROL_IPC		0x00000400	/* Checksum Offload */
> +#define GMAC_CONTROL_DR			0x00000200	/* Disable Retry */
> +#define GMAC_CONTROL_LUD		0x00000100	/* Link up/down */
> +#define GMAC_CONTROL_ACS		0x00000080	/* Auto Pad/FCS Stripping */
> +#define GMAC_CONTROL_DC			0x00000010	/* Deferral Check */
> +#define GMAC_CONTROL_TE			0x00000008	/* Transmitter Enable */
> +#define GMAC_CONTROL_RE			0x00000004	/* Receiver Enable */
> +
> +#define GMAC_CORE_INIT			(GMAC_CONTROL_JD | GMAC_CONTROL_PS | \
> +					 GMAC_CONTROL_BE | GMAC_CONTROL_DCRS | \
> +					 GMAC_CONTROL_ACS)
> +
> +/* GMAC Frame Filter defines */
> +#define GMAC_FRAME_FILTER_PR		0x00000001	/* Promiscuous Mode */
> +#define GMAC_FRAME_FILTER_HUC		0x00000002	/* Hash Unicast */
> +#define GMAC_FRAME_FILTER_HMC		0x00000004	/* Hash Multicast */
> +#define GMAC_FRAME_FILTER_DAIF		0x00000008	/* DA Inverse Filtering */
> +#define GMAC_FRAME_FILTER_PM		0x00000010	/* Pass all multicast */
> +#define GMAC_FRAME_FILTER_DBF		0x00000020	/* Disable Broadcast frames */
> +#define GMAC_FRAME_FILTER_PCF		0x00000080	/* Pass Control frames */
> +#define GMAC_FRAME_FILTER_SAIF		0x00000100	/* Inverse Filtering */
> +#define GMAC_FRAME_FILTER_SAF		0x00000200	/* Source Address Filter */
> +#define GMAC_FRAME_FILTER_HPF		0x00000400	/* Hash or perfect Filter */
> +#define GMAC_FRAME_FILTER_RA		0x80000000	/* Receive all mode */
> +/* GMII ADDR  defines */
> +#define GMAC_MII_ADDR_WRITE		0x00000002	/* MII Write */
> +#define GMAC_MII_ADDR_BUSY		0x00000001	/* MII Busy */
> +/* GMAC FLOW CTRL defines */
> +#define GMAC_FLOW_CTRL_PT_MASK		0xffff0000	/* Pause Time Mask */
> +#define GMAC_FLOW_CTRL_PT_SHIFT		16
> +#define GMAC_FLOW_CTRL_UP		0x00000008	/* Unicast pause frame enable */
> +#define GMAC_FLOW_CTRL_RFE		0x00000004	/* Rx Flow Control Enable */
> +#define GMAC_FLOW_CTRL_TFE		0x00000002	/* Tx Flow Control Enable */
> +#define GMAC_FLOW_CTRL_FCB_BPA		0x00000001	/* Flow Control Busy ... */
> +
> +/* DEBUG Register defines */
> +/* MTL TxStatus FIFO */
> +#define GMAC_DEBUG_TXSTSFSTS		BIT(25)	/* MTL TxStatus FIFO Full Status */
> +#define GMAC_DEBUG_TXFSTS		BIT(24) /* MTL Tx FIFO Not Empty Status */
> +#define GMAC_DEBUG_TWCSTS		BIT(22) /* MTL Tx FIFO Write Controller */
> +/* MTL Tx FIFO Read Controller Status */
> +#define GMAC_DEBUG_TRCSTS_MASK		GENMASK(21, 20)
> +#define GMAC_DEBUG_TRCSTS_SHIFT		20
> +#define GMAC_DEBUG_TRCSTS_IDLE		0
> +#define GMAC_DEBUG_TRCSTS_READ		1
> +#define GMAC_DEBUG_TRCSTS_TXW		2
> +#define GMAC_DEBUG_TRCSTS_WRITE		3
> +#define GMAC_DEBUG_TXPAUSED		BIT(19) /* MAC Transmitter in PAUSE */
> +/* MAC Transmit Frame Controller Status */
> +#define GMAC_DEBUG_TFCSTS_MASK		GENMASK(18, 17)
> +#define GMAC_DEBUG_TFCSTS_SHIFT		17
> +#define GMAC_DEBUG_TFCSTS_IDLE		0
> +#define GMAC_DEBUG_TFCSTS_WAIT		1
> +#define GMAC_DEBUG_TFCSTS_GEN_PAUSE	2
> +#define GMAC_DEBUG_TFCSTS_XFER		3
> +/* MAC GMII or MII Transmit Protocol Engine Status */
> +#define GMAC_DEBUG_TPESTS		BIT(16)
> +#define GMAC_DEBUG_RXFSTS_MASK		GENMASK(9, 8) /* MTL Rx FIFO Fill-level */
> +#define GMAC_DEBUG_RXFSTS_SHIFT		8
> +#define GMAC_DEBUG_RXFSTS_EMPTY		0
> +#define GMAC_DEBUG_RXFSTS_BT		1
> +#define GMAC_DEBUG_RXFSTS_AT		2
> +#define GMAC_DEBUG_RXFSTS_FULL		3
> +#define GMAC_DEBUG_RRCSTS_MASK		GENMASK(6, 5) /* MTL Rx FIFO Read Controller */
> +#define GMAC_DEBUG_RRCSTS_SHIFT		5
> +#define GMAC_DEBUG_RRCSTS_IDLE		0
> +#define GMAC_DEBUG_RRCSTS_RDATA		1
> +#define GMAC_DEBUG_RRCSTS_RSTAT		2
> +#define GMAC_DEBUG_RRCSTS_FLUSH		3
> +#define GMAC_DEBUG_RWCSTS		BIT(4) /* MTL Rx FIFO Write Controller Active */
> +/* MAC Receive Frame Controller FIFO Status */
> +#define GMAC_DEBUG_RFCFCSTS_MASK	GENMASK(2, 1)
> +#define GMAC_DEBUG_RFCFCSTS_SHIFT	1
> +/* MAC GMII or MII Receive Protocol Engine Status */
> +#define GMAC_DEBUG_RPESTS		BIT(0)
> +
> +/*--- DMA BLOCK defines ---*/
> +/* DMA Bus Mode register defines */
> +#define DMA_BUS_MODE_DA			0x00000002	/* Arbitration scheme */
> +#define DMA_BUS_MODE_DSL_MASK		0x0000007c	/* Descriptor Skip Length */
> +#define DMA_BUS_MODE_DSL_SHIFT		2		/*   (in DWORDS)      */
> +/* Programmable burst length (passed thorugh platform)*/
> +#define DMA_BUS_MODE_PBL_MASK		0x00003f00	/* Programmable Burst Len */
> +#define DMA_BUS_MODE_PBL_SHIFT		8
> +#define DMA_BUS_MODE_ATDS		0x00000080	/* Alternate Descriptor Size */
> +
> +enum rx_tx_priority_ratio {
> +	double_ratio = 0x00004000,	/* 2:1 */
> +	triple_ratio = 0x00008000,	/* 3:1 */
> +	quadruple_ratio = 0x0000c000,	/* 4:1 */
> +};
> +
> +#define DMA_BUS_MODE_FB			0x00010000	/* Fixed burst */
> +#define DMA_BUS_MODE_MB			0x04000000	/* Mixed burst */
> +#define DMA_BUS_MODE_RPBL_MASK		0x007e0000	/* Rx-Programmable Burst Len */
> +#define DMA_BUS_MODE_RPBL_SHIFT		17
> +#define DMA_BUS_MODE_USP		0x00800000
> +#define DMA_BUS_MODE_MAXPBL		0x01000000
> +#define DMA_BUS_MODE_AAL		0x02000000
> +
> +/* DMA CRS Control and Status Register Mapping */
> +#define DMA_HOST_TX_DESC		0x00001048	/* Current Host Tx descriptor */
> +#define DMA_HOST_RX_DESC		0x0000104c	/* Current Host Rx descriptor */
> +/*  DMA Bus Mode register defines */
> +#define DMA_BUS_PR_RATIO_MASK		0x0000c000	/* Rx/Tx priority ratio */
> +#define DMA_BUS_PR_RATIO_SHIFT		14
> +#define DMA_BUS_FB			0x00010000	/* Fixed Burst */
> +
> +/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
> +/* Disable Drop TCP/IP csum error */
> +#define DMA_CONTROL_DT			0x04000000
> +#define DMA_CONTROL_RSF			0x02000000	/* Receive Store and Forward */
> +#define DMA_CONTROL_DFF			0x01000000	/* Disaable flushing */
> +/* Threshold for Activating the FC */
> +enum rfa {
> +	act_full_minus_1 = 0x00800000,
> +	act_full_minus_2 = 0x00800200,
> +	act_full_minus_3 = 0x00800400,
> +	act_full_minus_4 = 0x00800600,
> +};
> +/* Threshold for Deactivating the FC */
> +enum rfd {
> +	deac_full_minus_1 = 0x00400000,
> +	deac_full_minus_2 = 0x00400800,
> +	deac_full_minus_3 = 0x00401000,
> +	deac_full_minus_4 = 0x00401800,
> +};
> +#define DMA_CONTROL_TSF	0x00200000	/* Transmit  Store and Forward */
> +
> +enum ttc_control {
> +	DMA_CONTROL_TTC_64 = 0x00000000,
> +	DMA_CONTROL_TTC_128 = 0x00004000,
> +	DMA_CONTROL_TTC_192 = 0x00008000,
> +	DMA_CONTROL_TTC_256 = 0x0000c000,
> +	DMA_CONTROL_TTC_40 = 0x00010000,
> +	DMA_CONTROL_TTC_32 = 0x00014000,
> +	DMA_CONTROL_TTC_24 = 0x00018000,
> +	DMA_CONTROL_TTC_16 = 0x0001c000,
> +};
> +#define DMA_CONTROL_TC_TX_MASK		0xfffe3fff
> +
> +#define DMA_CONTROL_EFC			0x00000100
> +#define DMA_CONTROL_FEF			0x00000080
> +#define DMA_CONTROL_FUF			0x00000040
> +
> +/* Receive flow control activation field
> + * RFA field in DMA control register, bits 23,10:9
> + */
> +#define DMA_CONTROL_RFA_MASK		0x00800600
> +
> +/* Receive flow control deactivation field
> + * RFD field in DMA control register, bits 22,12:11
> + */
> +#define DMA_CONTROL_RFD_MASK		0x00401800
> +
> +/* RFD and RFA fields are encoded as follows
> + *
> + *   Bit Field
> + *   0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled)
> + *   0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled)
> + *   0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled)
> + *   0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled)
> + *   1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled)
> + *   1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled)
> + *   1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled)
> + *   1,11 - Reserved
> + *
> + * RFD should always be > RFA for a given FIFO size. RFD == RFA may work,
> + * but packet throughput performance may not be as expected.
> + *
> + * Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame
> + * detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause
> + * Description).
> + *
> + * Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6),
> + * is set to 0. This allows pause frames with a quanta of 0 to be sent
> + * as an XOFF message to the link peer.
> + */
> +
> +#define RFA_FULL_MINUS_1K		0x00000000
> +#define RFA_FULL_MINUS_2K		0x00000200
> +#define RFA_FULL_MINUS_3K		0x00000400
> +#define RFA_FULL_MINUS_4K		0x00000600
> +#define RFA_FULL_MINUS_5K		0x00800000
> +#define RFA_FULL_MINUS_6K		0x00800200
> +#define RFA_FULL_MINUS_7K		0x00800400
> +
> +#define RFD_FULL_MINUS_1K		0x00000000
> +#define RFD_FULL_MINUS_2K		0x00000800
> +#define RFD_FULL_MINUS_3K		0x00001000
> +#define RFD_FULL_MINUS_4K		0x00001800
> +#define RFD_FULL_MINUS_5K		0x00400000
> +#define RFD_FULL_MINUS_6K		0x00400800
> +#define RFD_FULL_MINUS_7K		0x00401000
> +
> +enum rtc_control {
> +	DMA_CONTROL_RTC_64 = 0x00000000,
> +	DMA_CONTROL_RTC_32 = 0x00000008,
> +	DMA_CONTROL_RTC_96 = 0x00000010,
> +	DMA_CONTROL_RTC_128 = 0x00000018,
> +};
> +#define DMA_CONTROL_TC_RX_MASK		0xffffffe7
> +
> +#define DMA_CONTROL_OSF			0x00000004	/* Operate on second frame */
> +
> +/* MMC registers offset */
> +#define GMAC_MMC_CTRL			0x100
> +#define GMAC_MMC_RX_INTR		0x104
> +#define GMAC_MMC_TX_INTR		0x108
> +#define GMAC_MMC_RX_CSUM_OFFLOAD	0x208
> +#define GMAC_EXTHASH_BASE		0x500
> +
> +extern const struct stmmac_dma_ops dwegmac_dma_ops;
> +#endif /* __DWEGMAC_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c b/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
> new file mode 100644
> index 000000000000..4e0c8731adfb
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
> @@ -0,0 +1,552 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/crc32.h>
> +#include <linux/slab.h>
> +#include <linux/ethtool.h>
> +#include <linux/io.h>
> +#include "stmmac.h"
> +#include "stmmac_pcs.h"
> +#include "dwegmac.h"
> +
> +static void dwegmac_core_init(struct mac_device_info *hw,
> +			      struct net_device *dev)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value = readl(ioaddr + GMAC_CONTROL);
> +	int mtu = dev->mtu;
> +
> +	/* Configure GMAC core */
> +	value |= GMAC_CORE_INIT;
> +
> +	if (mtu > 1500)
> +		value |= GMAC_CONTROL_2K;
> +	if (mtu > 2000)
> +		value |= GMAC_CONTROL_JE;
> +
> +	if (hw->ps) {
> +		value |= GMAC_CONTROL_TE;
> +
> +		value &= ~hw->link.speed_mask;
> +		switch (hw->ps) {
> +		case SPEED_1000:
> +			value |= hw->link.speed1000;
> +			break;
> +		case SPEED_100:
> +			value |= hw->link.speed100;
> +			break;
> +		case SPEED_10:
> +			value |= hw->link.speed10;
> +			break;
> +		}
> +	}
> +
> +	writel(value, ioaddr + GMAC_CONTROL);
> +
> +	/* Mask GMAC interrupts */
> +	value = GMAC_INT_DEFAULT_MASK;
> +
> +	if (hw->pcs)
> +		value &= ~GMAC_INT_DISABLE_PCS;
> +
> +	writel(value, ioaddr + GMAC_INT_MASK);
> +
> +#ifdef STMMAC_VLAN_TAG_USED
> +	/* Tag detection without filtering */
> +	writel(0x0, ioaddr + GMAC_VLAN_TAG);
> +#endif
> +}
> +
> +static int dwegmac_rx_ipc_enable(struct mac_device_info *hw)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value = readl(ioaddr + GMAC_CONTROL);
> +
> +	if (hw->rx_csum)
> +		value |= GMAC_CONTROL_IPC;
> +	else
> +		value &= ~GMAC_CONTROL_IPC;
> +
> +	writel(value, ioaddr + GMAC_CONTROL);
> +
> +	value = readl(ioaddr + GMAC_CONTROL);
> +
> +	return !!(value & GMAC_CONTROL_IPC);
> +}
> +
> +static void dwegmac_dump_regs(struct mac_device_info *hw, u32 *reg_space)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	int i;
> +
> +	for (i = 0; i < 55; i++)
> +		reg_space[i] = readl(ioaddr + i * 4);
> +}
> +
> +static void dwegmac_set_umac_addr(struct stmmac_priv *priv,
> +				  struct mac_device_info *hw,
> +				  const unsigned char *addr,
> +				  unsigned int reg_n)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +
> +	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
> +			    GMAC_ADDR_LOW(reg_n));
> +}
> +
> +static void dwegmac_get_umac_addr(struct stmmac_priv *priv,
> +				  struct mac_device_info *hw,
> +				  unsigned char *addr,
> +				  unsigned int reg_n)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +
> +	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
> +			    GMAC_ADDR_LOW(reg_n));
> +}
> +
> +static void dwegmac_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
> +			       int mcbitslog2)
> +{
> +	int numhashregs, regs;
> +
> +	switch (mcbitslog2) {
> +	case 6:
> +		writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);
> +		writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);
> +		return;
> +	case 7:
> +		numhashregs = 4;
> +		break;
> +	case 8:
> +		numhashregs = 8;
> +		break;
> +	default:
> +		pr_debug("STMMAC: err in setting multicast filter\n");
> +		return;
> +	}
> +	for (regs = 0; regs < numhashregs; regs++)
> +		writel(mcfilterbits[regs],
> +		       ioaddr + GMAC_EXTHASH_BASE + regs * 4);
> +}
> +
> +static void dwegmac_set_filter(struct stmmac_priv *priv,
> +			       struct mac_device_info *hw,
> +			       struct net_device *dev)
> +{
> +	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
> +	unsigned int value = 0;
> +	unsigned int perfect_addr_number = hw->unicast_filter_entries;
> +	u32 mc_filter[8];
> +	int mcbitslog2 = hw->mcast_bits_log2;
> +
> +	pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
> +		 netdev_mc_count(dev), netdev_uc_count(dev));
> +
> +	memset(mc_filter, 0, sizeof(mc_filter));
> +
> +	if (dev->flags & IFF_PROMISC) {
> +		value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
> +	} else if (dev->flags & IFF_ALLMULTI) {
> +		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
> +	} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
> +		/* Fall back to all multicast if we've no filter */
> +		value = GMAC_FRAME_FILTER_PM;
> +	} else if (!netdev_mc_empty(dev)) {
> +		struct netdev_hw_addr *ha;
> +
> +		/* Hash filter for multicast */
> +		value = GMAC_FRAME_FILTER_HMC;
> +
> +		netdev_for_each_mc_addr(ha, dev) {
> +			/* The upper n bits of the calculated CRC are used to
> +			 * index the contents of the hash table. The number of
> +			 * bits used depends on the hardware configuration
> +			 * selected at core configuration time.
> +			 */
> +			int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
> +					      ETH_ALEN)) >>
> +					      (32 - mcbitslog2);
> +			/* The most significant bit determines the register to
> +			 * use (H/L) while the other 5 bits determine the bit
> +			 * within the register.
> +			 */
> +			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
> +		}
> +	}
> +
> +	value |= GMAC_FRAME_FILTER_HPF;
> +	dwegmac_set_mchash(ioaddr, mc_filter, mcbitslog2);
> +
> +	/* Handle multiple unicast addresses (perfect filtering) */
> +	if (netdev_uc_count(dev) > perfect_addr_number) {
> +		/* Switch to promiscuous mode if more than unicast
> +		 * addresses are requested than supported by hardware.
> +		 */
> +		value |= GMAC_FRAME_FILTER_PR;
> +	} else {
> +		int reg = 1;
> +		struct netdev_hw_addr *ha;
> +
> +		netdev_for_each_uc_addr(ha, dev) {
> +			stmmac_set_mac_addr(ioaddr, ha->addr,
> +					    GMAC_ADDR_HIGH(reg),
> +					    GMAC_ADDR_LOW(reg));
> +			reg++;
> +		}
> +
> +		while (reg < perfect_addr_number) {
> +			writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
> +			writel(0, ioaddr + GMAC_ADDR_LOW(reg));
> +			reg++;
> +		}
> +	}
> +
> +#ifdef FRAME_FILTER_DEBUG
> +	/* Enable Receive all mode (to debug filtering_fail errors) */
> +	value |= GMAC_FRAME_FILTER_RA;
> +#endif
> +	writel(value, ioaddr + GMAC_FRAME_FILTER);
> +}
> +
> +static void dwegmac_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
> +			      unsigned int fc, unsigned int pause_time,
> +			      u32 tx_cnt)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	/* Set flow such that DZPQ in Mac Register 6 is 0,
> +	 * and unicast pause detect is enabled.
> +	 */
> +	unsigned int flow = GMAC_FLOW_CTRL_UP;
> +
> +	pr_debug("GMAC Flow-Control:\n");
> +	if (fc & FLOW_RX) {
> +		pr_debug("\tReceive Flow-Control ON\n");
> +		flow |= GMAC_FLOW_CTRL_RFE;
> +	}
> +	if (fc & FLOW_TX) {
> +		pr_debug("\tTransmit Flow-Control ON\n");
> +		flow |= GMAC_FLOW_CTRL_TFE;
> +	}
> +
> +	if (duplex) {
> +		pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
> +		flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
> +	}
> +
> +	writel(flow, ioaddr + GMAC_FLOW_CTRL);
> +}
> +
> +static void dwegmac_pmt(struct mac_device_info *hw, unsigned long mode)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	unsigned int pmt = 0;
> +
> +	if (mode & WAKE_MAGIC) {
> +		pr_debug("GMAC: WOL Magic frame\n");
> +		pmt |= power_down | magic_pkt_en;
> +	}
> +	if (mode & WAKE_UCAST) {
> +		pr_debug("GMAC: WOL on global unicast\n");
> +		pmt |= power_down | global_unicast | wake_up_frame_en;
> +	}
> +
> +	writel(pmt, ioaddr + GMAC_PMT);
> +}
> +
> +/* RGMII or SMII interface */
> +static void dwegmac_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
> +{
> +	u32 status;
> +
> +	status = readl(ioaddr + GMAC_RGSMIIIS);
> +	x->irq_rgmii_n++;
> +
> +	/* Check the link status */
> +	if (status & GMAC_RGSMIIIS_LNKSTS) {
> +		int speed_value;
> +
> +		x->pcs_link = 1;
> +
> +		speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
> +			       GMAC_RGSMIIIS_SPEED_SHIFT);
> +		if (speed_value == GMAC_RGSMIIIS_SPEED_125)
> +			x->pcs_speed = SPEED_1000;
> +		else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
> +			x->pcs_speed = SPEED_100;
> +		else
> +			x->pcs_speed = SPEED_10;
> +
> +		x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
> +
> +		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
> +			x->pcs_duplex ? "Full" : "Half");
> +	} else {
> +		x->pcs_link = 0;
> +		pr_info("Link is Down\n");
> +	}
> +}
> +
> +static int dwegmac_irq_status(struct mac_device_info *hw,
> +			      struct stmmac_extra_stats *x)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
> +	u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
> +	int ret = 0;
> +
> +	/* Discard masked bits */
> +	intr_status &= ~intr_mask;
> +
> +	/* Not used events (e.g. MMC interrupts) are not handled. */
> +	if ((intr_status & GMAC_INT_STATUS_MMCTIS))
> +		x->mmc_tx_irq_n++;
> +	if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
> +		x->mmc_rx_irq_n++;
> +	if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
> +		x->mmc_rx_csum_offload_irq_n++;
> +	if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
> +		/* clear the PMT bits 5 and 6 by reading the PMT status reg */
> +		readl(ioaddr + GMAC_PMT);
> +		x->irq_receive_pmt_irq_n++;
> +	}
> +
> +	/* MAC tx/rx EEE LPI entry/exit interrupts */
> +	if (intr_status & GMAC_INT_STATUS_LPIIS) {
> +		/* Clean LPI interrupt by reading the Reg 12 */
> +		ret = readl(ioaddr + LPI_CTRL_STATUS);
> +
> +		if (ret & LPI_CTRL_STATUS_TLPIEN)
> +			x->irq_tx_path_in_lpi_mode_n++;
> +		if (ret & LPI_CTRL_STATUS_TLPIEX)
> +			x->irq_tx_path_exit_lpi_mode_n++;
> +		if (ret & LPI_CTRL_STATUS_RLPIEN)
> +			x->irq_rx_path_in_lpi_mode_n++;
> +		if (ret & LPI_CTRL_STATUS_RLPIEX)
> +			x->irq_rx_path_exit_lpi_mode_n++;
> +	}
> +
> +	dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
> +
> +	if (intr_status & PCS_RGSMIIIS_IRQ)
> +		dwegmac_rgsmii(ioaddr, x);
> +
> +	return ret;
> +}
> +
> +static void dwegmac_set_eee_mode(struct mac_device_info *hw,
> +				 bool en_tx_lpi_clockgating)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value;
> +
> +	/*TODO - en_tx_lpi_clockgating treatment */
> +
> +	/* Enable the link status receive on RGMII, SGMII ore SMII
> +	 * receive path and instruct the transmit to enter in LPI
> +	 * state.
> +	 */
> +	value = readl(ioaddr + LPI_CTRL_STATUS);
> +	value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
> +	writel(value, ioaddr + LPI_CTRL_STATUS);
> +}
> +
> +static void dwegmac_reset_eee_mode(struct mac_device_info *hw)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value;
> +
> +	value = readl(ioaddr + LPI_CTRL_STATUS);
> +	value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
> +	writel(value, ioaddr + LPI_CTRL_STATUS);
> +}
> +
> +static void dwegmac_set_eee_pls(struct mac_device_info *hw, int link)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value;
> +
> +	value = readl(ioaddr + LPI_CTRL_STATUS);
> +
> +	if (link)
> +		value |= LPI_CTRL_STATUS_PLS;
> +	else
> +		value &= ~LPI_CTRL_STATUS_PLS;
> +
> +	writel(value, ioaddr + LPI_CTRL_STATUS);
> +}
> +
> +static void dwegmac_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
> +
> +	/* Program the timers in the LPI timer control register:
> +	 * LS: minimum time (ms) for which the link
> +	 *  status from PHY should be ok before transmitting
> +	 *  the LPI pattern.
> +	 * TW: minimum time (us) for which the core waits
> +	 *  after it has stopped transmitting the LPI pattern.
> +	 */
> +	writel(value, ioaddr + LPI_TIMER_CTRL);
> +}
> +
> +static void dwegmac_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
> +			     bool loopback)
> +{
> +	dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
> +}
> +
> +static void dwegmac_rane(void __iomem *ioaddr, bool restart)
> +{
> +	dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
> +}
> +
> +static void dwegmac_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
> +{
> +	dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
> +}
> +
> +static void dwegmac_debug(struct stmmac_priv *priv, void __iomem *ioaddr,
> +			  struct stmmac_extra_stats *x,
> +			  u32 rx_queues, u32 tx_queues)
> +{
> +	u32 value = readl(ioaddr + GMAC_DEBUG);
> +
> +	if (value & GMAC_DEBUG_TXSTSFSTS)
> +		x->mtl_tx_status_fifo_full++;
> +	if (value & GMAC_DEBUG_TXFSTS)
> +		x->mtl_tx_fifo_not_empty++;
> +	if (value & GMAC_DEBUG_TWCSTS)
> +		x->mmtl_fifo_ctrl++;
> +	if (value & GMAC_DEBUG_TRCSTS_MASK) {
> +		u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK)
> +			     >> GMAC_DEBUG_TRCSTS_SHIFT;
> +		if (trcsts == GMAC_DEBUG_TRCSTS_WRITE)
> +			x->mtl_tx_fifo_read_ctrl_write++;
> +		else if (trcsts == GMAC_DEBUG_TRCSTS_TXW)
> +			x->mtl_tx_fifo_read_ctrl_wait++;
> +		else if (trcsts == GMAC_DEBUG_TRCSTS_READ)
> +			x->mtl_tx_fifo_read_ctrl_read++;
> +		else
> +			x->mtl_tx_fifo_read_ctrl_idle++;
> +	}
> +	if (value & GMAC_DEBUG_TXPAUSED)
> +		x->mac_tx_in_pause++;
> +	if (value & GMAC_DEBUG_TFCSTS_MASK) {
> +		u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK)
> +			      >> GMAC_DEBUG_TFCSTS_SHIFT;
> +
> +		if (tfcsts == GMAC_DEBUG_TFCSTS_XFER)
> +			x->mac_tx_frame_ctrl_xfer++;
> +		else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE)
> +			x->mac_tx_frame_ctrl_pause++;
> +		else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT)
> +			x->mac_tx_frame_ctrl_wait++;
> +		else
> +			x->mac_tx_frame_ctrl_idle++;
> +	}
> +	if (value & GMAC_DEBUG_TPESTS)
> +		x->mac_gmii_tx_proto_engine++;
> +	if (value & GMAC_DEBUG_RXFSTS_MASK) {
> +		u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK)
> +			     >> GMAC_DEBUG_RRCSTS_SHIFT;
> +
> +		if (rxfsts == GMAC_DEBUG_RXFSTS_FULL)
> +			x->mtl_rx_fifo_fill_level_full++;
> +		else if (rxfsts == GMAC_DEBUG_RXFSTS_AT)
> +			x->mtl_rx_fifo_fill_above_thresh++;
> +		else if (rxfsts == GMAC_DEBUG_RXFSTS_BT)
> +			x->mtl_rx_fifo_fill_below_thresh++;
> +		else
> +			x->mtl_rx_fifo_fill_level_empty++;
> +	}
> +	if (value & GMAC_DEBUG_RRCSTS_MASK) {
> +		u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >>
> +			     GMAC_DEBUG_RRCSTS_SHIFT;
> +
> +		if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH)
> +			x->mtl_rx_fifo_read_ctrl_flush++;
> +		else if (rrcsts == GMAC_DEBUG_RRCSTS_RSTAT)
> +			x->mtl_rx_fifo_read_ctrl_read_data++;
> +		else if (rrcsts == GMAC_DEBUG_RRCSTS_RDATA)
> +			x->mtl_rx_fifo_read_ctrl_status++;
> +		else
> +			x->mtl_rx_fifo_read_ctrl_idle++;
> +	}
> +	if (value & GMAC_DEBUG_RWCSTS)
> +		x->mtl_rx_fifo_ctrl_active++;
> +	if (value & GMAC_DEBUG_RFCFCSTS_MASK)
> +		x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK)
> +					    >> GMAC_DEBUG_RFCFCSTS_SHIFT;
> +	if (value & GMAC_DEBUG_RPESTS)
> +		x->mac_gmii_rx_proto_engine++;
> +}
> +
> +static void dwegmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
> +{
> +	u32 value = readl(ioaddr + GMAC_CONTROL);
> +
> +	if (enable)
> +		value |= GMAC_CONTROL_LM;
> +	else
> +		value &= ~GMAC_CONTROL_LM;
> +
> +	writel(value, ioaddr + GMAC_CONTROL);
> +}
> +
> +const struct stmmac_ops dwegmac_ops = {
> +	.core_init = dwegmac_core_init,
> +	.set_mac = stmmac_set_mac,
> +	.rx_ipc = dwegmac_rx_ipc_enable,
> +	.dump_regs = dwegmac_dump_regs,
> +	.host_irq_status = dwegmac_irq_status,
> +	.set_filter = dwegmac_set_filter,
> +	.flow_ctrl = dwegmac_flow_ctrl,
> +	.pmt = dwegmac_pmt,
> +	.set_umac_addr = dwegmac_set_umac_addr,
> +	.get_umac_addr = dwegmac_get_umac_addr,
> +	.set_eee_mode = dwegmac_set_eee_mode,
> +	.reset_eee_mode = dwegmac_reset_eee_mode,
> +	.set_eee_timer = dwegmac_set_eee_timer,
> +	.set_eee_pls = dwegmac_set_eee_pls,
> +	.debug = dwegmac_debug,
> +	.pcs_ctrl_ane = dwegmac_ctrl_ane,
> +	.pcs_rane = dwegmac_rane,
> +	.pcs_get_adv_lp = dwegmac_get_adv_lp,
> +	.set_mac_loopback = dwegmac_set_mac_loopback,
> +};
> +
> +int dwegmac_setup(struct stmmac_priv *priv)
> +{
> +	struct mac_device_info *mac = priv->hw;
> +
> +	dev_info(priv->device, "\tExtended DWMAC\n");
> +
> +	priv->dev->priv_flags |= IFF_UNICAST_FLT;
> +	mac->pcsr = priv->ioaddr;
> +	mac->multicast_filter_bins = priv->plat->multicast_filter_bins;
> +	mac->unicast_filter_entries = priv->plat->unicast_filter_entries;
> +	mac->mcast_bits_log2 = 0;
> +
> +	if (mac->multicast_filter_bins)
> +		mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
> +
> +	mac->link.duplex = GMAC_CONTROL_DM;
> +	mac->link.speed10 = GMAC_CONTROL_PS;
> +	mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
> +	mac->link.speed1000 = 0;
> +	mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
> +	mac->mii.addr = GMAC_MII_ADDR;
> +	mac->mii.data = GMAC_MII_DATA;
> +	mac->mii.addr_shift = 11;
> +	mac->mii.addr_mask = 0x0000F800;
> +	mac->mii.reg_shift = 6;
> +	mac->mii.reg_mask = 0x000007C0;
> +	mac->mii.clk_csr_shift = 2;
> +	mac->mii.clk_csr_mask = GENMASK(5, 2);
> +
> +	return 0;
> +}
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
> new file mode 100644
> index 000000000000..9bb0564fbeff
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
> @@ -0,0 +1,516 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/io.h>
> +#include "stmmac.h"
> +#include "dwegmac.h"
> +#include "dwegmac_dma.h"
> +
> +static int dwegmac_dma_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
> +{
> +	u32 value = readl(ioaddr + DMA_BUS_MODE);
> +
> +	value |= DMA_BUS_MODE_SFT_RESET;
> +	writel(value, ioaddr + DMA_BUS_MODE);
> +
> +	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
> +				 !(value & DMA_BUS_MODE_SFT_RESET),
> +				 10000, 200000);
> +}
> +
> +static void dwegmac_enable_dma_transmission(struct stmmac_priv *priv,
> +					    void __iomem *ioaddr, u32 chan)
> +{
> +	writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));
> +}
> +
> +static void dwegmac_enable_dma_irq(struct stmmac_priv *priv,
> +				   void __iomem *ioaddr,
> +				   u32 chan, bool rx, bool tx)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
> +
> +	if (rx)
> +		value |= DMA_INTR_DEFAULT_RX;
> +	if (tx)
> +		value |= DMA_INTR_DEFAULT_TX;
> +
> +	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
> +}
> +
> +static void dwegmac_disable_dma_irq(struct stmmac_priv *priv,
> +				    void __iomem *ioaddr,
> +				    u32 chan, bool rx, bool tx)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
> +
> +	if (rx)
> +		value &= ~DMA_INTR_DEFAULT_RX;
> +	if (tx)
> +		value &= ~DMA_INTR_DEFAULT_TX;
> +
> +	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
> +}
> +
> +static void dwegmac_dma_start_tx(struct stmmac_priv *priv,
> +				 void __iomem *ioaddr, u32 chan)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
> +
> +	value |= DMA_CONTROL_ST;
> +	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
> +}
> +
> +static void dwegmac_dma_stop_tx(struct stmmac_priv *priv,
> +				void __iomem *ioaddr, u32 chan)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
> +
> +	value &= ~DMA_CONTROL_ST;
> +	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
> +}
> +
> +static void dwegmac_dma_start_rx(struct stmmac_priv *priv,
> +				 void __iomem *ioaddr, u32 chan)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
> +
> +	value |= DMA_CONTROL_SR;
> +	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
> +}
> +
> +static void dwegmac_dma_stop_rx(struct stmmac_priv *priv,
> +				void __iomem *ioaddr, u32 chan)
> +{
> +	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
> +
> +	value &= ~DMA_CONTROL_SR;
> +	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
> +}
> +
> +static int dwegmac_dma_interrupt(struct stmmac_priv *priv,
> +				 void __iomem *ioaddr,
> +				 struct stmmac_extra_stats *x,
> +				 u32 chan, u32 dir)
> +{
> +	int ret = 0;
> +	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
> +
> +	if (dir == DMA_DIR_RX)
> +		intr_status &= DMA_STATUS_MSK_RX;
> +	else if (dir == DMA_DIR_TX)
> +		intr_status &= DMA_STATUS_MSK_TX;
> +
> +	/* ABNORMAL interrupts */
> +	if (unlikely(intr_status & (DMA_STATUS_TX_AIS | DMA_STATUS_RX_AIS))) {
> +		if (unlikely(intr_status & DMA_STATUS_UNF)) {
> +			ret = tx_hard_error_bump_tc;
> +			x->tx_undeflow_irq++;
> +		}
> +		if (unlikely(intr_status & DMA_STATUS_TJT))
> +			x->tx_jabber_irq++;
> +
> +		if (unlikely(intr_status & DMA_STATUS_OVF))
> +			x->rx_overflow_irq++;
> +
> +		if (unlikely(intr_status & DMA_STATUS_RU))
> +			x->rx_buf_unav_irq++;
> +		if (unlikely(intr_status & DMA_STATUS_RPS))
> +			x->rx_process_stopped_irq++;
> +		if (unlikely(intr_status & DMA_STATUS_RWT))
> +			x->rx_watchdog_irq++;
> +		if (unlikely(intr_status & DMA_STATUS_ETI))
> +			x->tx_early_irq++;
> +		if (unlikely(intr_status & DMA_STATUS_TPS)) {
> +			x->tx_process_stopped_irq++;
> +			ret = tx_hard_error;
> +		}
> +		if (unlikely(intr_status &
> +			     (DMA_STATUS_TX_FBI | DMA_STATUS_RX_FBI))) {
> +			x->fatal_bus_error_irq++;
> +			ret = tx_hard_error;
> +		}
> +	}
> +	/* TX/RX NORMAL interrupts */
> +	if (likely(intr_status & (DMA_STATUS_TX_NIS | DMA_STATUS_RX_NIS))) {
> +		x->normal_irq_n++;
> +		if (likely(intr_status & DMA_STATUS_RI)) {
> +			u32 value = readl(ioaddr + DMA_INTR_ENA);
> +			/* to schedule NAPI on real RIE event. */
> +			if (likely(value & DMA_INTR_ENA_RIE)) {
> +				x->rx_normal_irq_n++;
> +				ret |= handle_rx;
> +			}
> +		}
> +		if (likely(intr_status & DMA_STATUS_TI)) {
> +			x->tx_normal_irq_n++;
> +			ret |= handle_tx;
> +		}
> +		if (unlikely(intr_status & DMA_STATUS_ERI))
> +			x->rx_early_irq++;
> +	}
> +
> +	writel((intr_status & 0x7ffff), ioaddr + DMA_CHAN_STATUS(chan));
> +
> +	return ret;
> +}
> +
> +static void dwegmac_dma_axi(struct stmmac_priv *priv, void __iomem *ioaddr,
> +			    struct stmmac_axi *axi)
> +{
> +	u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
> +	int i;
> +
> +	pr_info("dwegmac: Master AXI performs %s burst length\n",
> +		!(value & DMA_AXI_UNDEF) ? "fixed" : "any");
> +
> +	if (axi->axi_lpi_en)
> +		value |= DMA_AXI_EN_LPI;
> +	if (axi->axi_xit_frm)
> +		value |= DMA_AXI_LPI_XIT_FRM;
> +
> +	if (priv->plat->dma_cfg->dma64) {
> +		value &= ~DMA_AXI_WR_OSR64_LMT;
> +		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR64_LMT_MASK) <<
> +			 DMA_AXI_WR_OSR64_LMT_SHIFT;
> +
> +		value &= ~DMA_AXI_RD_OSR64_LMT;
> +		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR64_LMT_MASK) <<
> +			 DMA_AXI_RD_OSR64_LMT_SHIFT;
> +	} else {
> +		value &= ~DMA_AXI_WR_OSR_LMT;
> +		value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
> +			 DMA_AXI_WR_OSR_LMT_SHIFT;
> +
> +		value &= ~DMA_AXI_RD_OSR_LMT;
> +		value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
> +			 DMA_AXI_RD_OSR_LMT_SHIFT;
> +	}
> +
> +	/* Depending on the UNDEF bit the Master AXI will perform any burst
> +	 * length according to the BLEN programmed (by default all BLEN are
> +	 * set).
> +	 */
> +	for (i = 0; i < AXI_BLEN; i++) {
> +		switch (axi->axi_blen[i]) {
> +		case 256:
> +			value |= DMA_AXI_BLEN256;
> +			break;
> +		case 128:
> +			value |= DMA_AXI_BLEN128;
> +			break;
> +		case 64:
> +			value |= DMA_AXI_BLEN64;
> +			break;
> +		case 32:
> +			value |= DMA_AXI_BLEN32;
> +			break;
> +		case 16:
> +			value |= DMA_AXI_BLEN16;
> +			break;
> +		case 8:
> +			value |= DMA_AXI_BLEN8;
> +			break;
> +		case 4:
> +			value |= DMA_AXI_BLEN4;
> +			break;
> +		}
> +	}
> +
> +	writel(value, ioaddr + DMA_AXI_BUS_MODE);
> +}
> +
> +static void dwegmac_dma_init(struct stmmac_priv *priv, void __iomem *ioaddr,
> +			     struct stmmac_dma_cfg *dma_cfg, int atds)
> +{
> +	u32 value = readl(ioaddr + DMA_BUS_MODE);
> +	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
> +	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
> +
> +	/* Set the DMA PBL (Programmable Burst Length) mode.
> +	 *
> +	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
> +	 * post 3.5 mode bit acts as 8*PBL.
> +	 */
> +	if (dma_cfg->pblx8)
> +		value |= DMA_BUS_MODE_MAXPBL;
> +	value |= DMA_BUS_MODE_USP;
> +	value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
> +	value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
> +	value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
> +
> +	/* Set the Fixed burst mode */
> +	if (dma_cfg->fixed_burst)
> +		value |= DMA_BUS_MODE_FB;
> +
> +	/* Mixed Burst has no effect when fb is set */
> +	if (dma_cfg->mixed_burst)
> +		value |= DMA_BUS_MODE_MB;
> +
> +	if (atds)
> +		value |= DMA_BUS_MODE_ATDS;
> +
> +	if (dma_cfg->aal)
> +		value |= DMA_BUS_MODE_AAL;
> +
> +	writel(value, ioaddr + DMA_BUS_MODE);
> +
> +	/* Mask interrupts by writing to CSR7 */
> +	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
> +}
> +
> +static void dwegmac_dma_init_channel(struct stmmac_priv *priv,
> +				     void __iomem *ioaddr,
> +				     struct stmmac_dma_cfg *dma_cfg,
> +				     u32 chan)
> +{
> +	u32 value;
> +	int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
> +	int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
> +
> +	if (!priv->plat->multi_msi_en)
> +		return;
> +
> +	/* common channel control register config */
> +	value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
> +
> +	/* Set the DMA PBL (Programmable Burst Length) mode.
> +	 *
> +	 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
> +	 * post 3.5 mode bit acts as 8*PBL.
> +	 */
> +	if (dma_cfg->pblx8)
> +		value |= DMA_BUS_MODE_MAXPBL;
> +	value |= DMA_BUS_MODE_USP;
> +	value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
> +	value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
> +	value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
> +
> +	/* Set the Fixed burst mode */
> +	if (dma_cfg->fixed_burst)
> +		value |= DMA_BUS_MODE_FB;
> +
> +	/* Mixed Burst has no effect when fb is set */
> +	if (dma_cfg->mixed_burst)
> +		value |= DMA_BUS_MODE_MB;
> +
> +	value |= DMA_BUS_MODE_ATDS;
> +
> +	if (dma_cfg->aal)
> +		value |= DMA_BUS_MODE_AAL;
> +
> +	writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
> +
> +	/* Mask interrupts by writing to CSR7 */
> +	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
> +
> +	if (dma_cfg->dma64)
> +		writel(0x100, ioaddr + DMA_CHAN_NEWFUNC_CONFIG(chan));
> +}
> +
> +static void dwegmac_dma_init_rx(struct stmmac_priv *priv,
> +				void __iomem *ioaddr,
> +				struct stmmac_dma_cfg *dma_cfg,
> +				dma_addr_t dma_rx_phy, u32 chan)
> +{
> +	if (dma_cfg->dma64) {
> +		writel(lower_32_bits(dma_rx_phy), ioaddr +
> +		       DMA_CHAN_RCV_BASE_ADDR64(chan));
> +		writel(upper_32_bits(dma_rx_phy), ioaddr +
> +		       DMA_CHAN_RCV_BASE_ADDR64_HI(chan));
> +		writel(upper_32_bits(dma_rx_phy), ioaddr +
> +		       DMA_RCV_BASE_ADDR64_HI_SHADOW1);
> +		writel(upper_32_bits(dma_rx_phy), ioaddr +
> +		       DMA_RCV_BASE_ADDR64_HI_SHADOW2);
> +	} else {
> +		writel(lower_32_bits(dma_rx_phy), ioaddr +
> +		       DMA_CHAN_RCV_BASE_ADDR(chan));
> +	}
> +}
> +
> +static void dwegmac_dma_init_tx(struct stmmac_priv *priv,
> +				void __iomem *ioaddr,
> +				struct stmmac_dma_cfg *dma_cfg,
> +				dma_addr_t dma_tx_phy, u32 chan)
> +{
> +	if (dma_cfg->dma64) {
> +		writel(lower_32_bits(dma_tx_phy), ioaddr +
> +		       DMA_CHAN_TX_BASE_ADDR64(chan));
> +		writel(upper_32_bits(dma_tx_phy), ioaddr +
> +		       DMA_CHAN_TX_BASE_ADDR64_HI(chan));
> +	} else {
> +		writel(lower_32_bits(dma_tx_phy), ioaddr +
> +		       DMA_CHAN_TX_BASE_ADDR(chan));
> +	}
> +}
> +
> +static u32 dwegmac_configure_fc(u32 csr6, int rxfifosz)
> +{
> +	csr6 &= ~DMA_CONTROL_RFA_MASK;
> +	csr6 &= ~DMA_CONTROL_RFD_MASK;
> +
> +	/* Leave flow control disabled if receive fifo size is less than
> +	 * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
> +	 * and send XON when 2K less than full.
> +	 */
> +	if (rxfifosz < 4096) {
> +		csr6 &= ~DMA_CONTROL_EFC;
> +		pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
> +			 rxfifosz);
> +	} else {
> +		csr6 |= DMA_CONTROL_EFC;
> +		csr6 |= RFA_FULL_MINUS_1K;
> +		csr6 |= RFD_FULL_MINUS_2K;
> +	}
> +	return csr6;
> +}
> +
> +static void dwegmac_dma_operation_mode_rx(struct stmmac_priv *priv,
> +					  void __iomem *ioaddr, int mode,
> +					  u32 channel, int fifosz, u8 qmode)
> +{
> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
> +
> +	if (mode == SF_DMA_MODE) {
> +		pr_debug("GMAC: enable RX store and forward mode\n");
> +		csr6 |= DMA_CONTROL_RSF;
> +	} else {
> +		pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
> +		csr6 &= ~DMA_CONTROL_RSF;
> +		csr6 &= DMA_CONTROL_TC_RX_MASK;
> +		if (mode <= 32)
> +			csr6 |= DMA_CONTROL_RTC_32;
> +		else if (mode <= 64)
> +			csr6 |= DMA_CONTROL_RTC_64;
> +		else if (mode <= 96)
> +			csr6 |= DMA_CONTROL_RTC_96;
> +		else
> +			csr6 |= DMA_CONTROL_RTC_128;
> +	}
> +
> +	/* Configure flow control based on rx fifo size */
> +	csr6 = dwegmac_configure_fc(csr6, fifosz);
> +
> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
> +}
> +
> +static void dwegmac_dma_operation_mode_tx(struct stmmac_priv *priv,
> +					  void __iomem *ioaddr, int mode,
> +					  u32 channel, int fifosz, u8 qmode)
> +{
> +	u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
> +
> +	if (mode == SF_DMA_MODE) {
> +		pr_debug("GMAC: enable TX store and forward mode\n");
> +		/* Transmit COE type 2 cannot be done in cut-through mode. */
> +		csr6 |= DMA_CONTROL_TSF;
> +		/* Operating on second frame increase the performance
> +		 * especially when transmit store-and-forward is used.
> +		 */
> +		csr6 |= DMA_CONTROL_OSF;
> +	} else {
> +		pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
> +		csr6 &= ~DMA_CONTROL_TSF;
> +		csr6 &= DMA_CONTROL_TC_TX_MASK;
> +		/* Set the transmit threshold */
> +		if (mode <= 32)
> +			csr6 |= DMA_CONTROL_TTC_32;
> +		else if (mode <= 64)
> +			csr6 |= DMA_CONTROL_TTC_64;
> +		else if (mode <= 128)
> +			csr6 |= DMA_CONTROL_TTC_128;
> +		else if (mode <= 192)
> +			csr6 |= DMA_CONTROL_TTC_192;
> +		else
> +			csr6 |= DMA_CONTROL_TTC_256;
> +	}
> +
> +	writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
> +}
> +
> +static void dwegmac_dump_dma_regs(struct stmmac_priv *priv,
> +				  void __iomem *ioaddr, u32 *reg_space)
> +{
> +	int i;
> +
> +	for (i = 0; i < NUM_DWEGMAC_DMA_REGS; i++)
> +		if (i < 12 || i > 17)
> +			reg_space[DMA_BUS_MODE / 4 + i] =
> +				readl(ioaddr + DMA_BUS_MODE + i * 4);
> +}
> +
> +static int dwegmac_get_hw_feature(struct stmmac_priv *priv,
> +				  void __iomem *ioaddr,
> +				  struct dma_features *dma_cap)
> +{
> +	u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
> +
> +	if (!hw_cap) {
> +		/* 0x00000000 is the value read on old hardware that does not
> +		 * implement this register
> +		 */
> +		return -EOPNOTSUPP;
> +	}
> +
> +	dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
> +	dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
> +	dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
> +	dma_cap->hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
> +	dma_cap->multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
> +	dma_cap->pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
> +	dma_cap->sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
> +	dma_cap->pmt_remote_wake_up = (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
> +	dma_cap->pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
> +	/* MMC */
> +	dma_cap->rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
> +	/* IEEE 1588-2002 */
> +	dma_cap->time_stamp =
> +	    (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
> +	/* IEEE 1588-2008 */
> +	dma_cap->atime_stamp = (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
> +	/* 802.3az - Energy-Efficient Ethernet (EEE) */
> +	dma_cap->eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
> +	dma_cap->av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
> +	/* TX and RX csum */
> +	dma_cap->tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
> +	dma_cap->rx_coe_type1 = (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
> +	dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
> +	dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
> +	/* TX and RX number of channels */
> +	dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
> +	dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
> +	/* Alternate (enhanced) DESC mode */
> +	dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
> +
> +	return 0;
> +}
> +
> +static void dwegmac_rx_watchdog(struct stmmac_priv *priv,
> +				void __iomem *ioaddr, u32 riwt, u32 queue)
> +{
> +	writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
> +}
> +
> +const struct stmmac_dma_ops dwegmac_dma_ops = {
> +	.reset = dwegmac_dma_reset,
> +	.init = dwegmac_dma_init,
> +	.init_chan = dwegmac_dma_init_channel,
> +	.init_rx_chan = dwegmac_dma_init_rx,
> +	.init_tx_chan = dwegmac_dma_init_tx,
> +	.axi = dwegmac_dma_axi,
> +	.dump_regs = dwegmac_dump_dma_regs,
> +	.dma_rx_mode = dwegmac_dma_operation_mode_rx,
> +	.dma_tx_mode = dwegmac_dma_operation_mode_tx,
> +	.enable_dma_transmission = dwegmac_enable_dma_transmission,
> +	.enable_dma_irq = dwegmac_enable_dma_irq,
> +	.disable_dma_irq = dwegmac_disable_dma_irq,
> +	.start_tx = dwegmac_dma_start_tx,
> +	.stop_tx = dwegmac_dma_stop_tx,
> +	.start_rx = dwegmac_dma_start_rx,
> +	.stop_rx = dwegmac_dma_stop_rx,
> +	.dma_interrupt = dwegmac_dma_interrupt,
> +	.get_hw_feature = dwegmac_get_hw_feature,
> +	.rx_watchdog = dwegmac_rx_watchdog,
> +};
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
> new file mode 100644
> index 000000000000..aadc13eae502
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __DWEGMAC_DMA_H__
> +#define __DWEGMAC_DMA_H__
> +
> +/* DMA CRS Control and Status Register Mapping */
> +#define DMA_BUS_MODE			0x00001000	/* Bus Mode */
> +#define DMA_XMT_POLL_DEMAND		0x00001004	/* Transmit Poll Demand */
> +#define DMA_RCV_POLL_DEMAND		0x00001008	/* Received Poll Demand */
> +#define DMA_RCV_BASE_ADDR		0x0000100c	/* Receive List Base */
> +#define DMA_RCV_BASE_ADDR64		0x00001090
> +#define DMA_RCV_BASE_ADDR64_HI		0x00001094
> +#define DMA_RCV_BASE_ADDR64_HI_SHADOW1	0x00001068
> +#define DMA_RCV_BASE_ADDR64_HI_SHADOW2	0x000010a8
> +#define DMA_TX_BASE_ADDR		0x00001010	/* Transmit List Base */
> +#define DMA_TX_BASE_ADDR64		0x00001098
> +#define DMA_TX_BASE_ADDR64_HI		0x0000109c
> +#define DMA_STATUS			0x00001014	/* Status Register */
> +#define DMA_CONTROL			0x00001018	/* Ctrl (Operational Mode) */
> +#define DMA_INTR_ENA			0x0000101c	/* Interrupt Enable */
> +#define DMA_MISSED_FRAME_CTR		0x00001020	/* Missed Frame Counter */
> +#define DMA_NEWFUNC_CONFIG		0x00001080	/* New Function Config */
> +
> +/* SW Reset */
> +#define DMA_BUS_MODE_SFT_RESET		0x00000001	/* Software Reset */
> +
> +/* Rx watchdog register */
> +#define DMA_RX_WATCHDOG			0x00001024
> +
> +/* AXI Master Bus Mode */
> +#define DMA_AXI_BUS_MODE		0x00001028
> +
> +#define DMA_AXI_EN_LPI			BIT(31)
> +#define DMA_AXI_LPI_XIT_FRM		BIT(30)
> +#define DMA_AXI_WR_OSR_LMT		GENMASK(23, 20)
> +#define DMA_AXI_WR_OSR_LMT_SHIFT	20
> +#define DMA_AXI_WR_OSR_LMT_MASK		0xf
> +#define DMA_AXI_RD_OSR_LMT		GENMASK(19, 16)
> +#define DMA_AXI_RD_OSR_LMT_SHIFT	16
> +#define DMA_AXI_RD_OSR_LMT_MASK		0xf
> +#define DMA_AXI_WR_OSR64_LMT		GENMASK(21, 20)
> +#define DMA_AXI_WR_OSR64_LMT_SHIFT	20
> +#define DMA_AXI_WR_OSR64_LMT_MASK	0x3
> +#define DMA_AXI_RD_OSR64_LMT		GENMASK(17, 16)
> +#define DMA_AXI_RD_OSR64_LMT_SHIFT	16
> +#define DMA_AXI_RD_OSR64_LMT_MASK	0x3
> +
> +#define DMA_AXI_OSR_MAX			0xf
> +#define DMA_AXI_MAX_OSR_LIMIT		((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
> +					 (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
> +#define DMA_AXI_OSR64_MAX		0x3
> +#define DMA_AXI_MAX_OSR64_LIMIT		((DMA_AXI_OSR64_MAX << DMA_AXI_WR_OSR64_LMT_SHIFT) | \
> +					 (DMA_AXI_OSR64_MAX << DMA_AXI_RD_OSR64_LMT_SHIFT))
> +#define	DMA_AXI_1KBBE			BIT(13)
> +#define DMA_AXI_AAL			BIT(12)
> +#define DMA_AXI_BLEN256			BIT(7)
> +#define DMA_AXI_BLEN128			BIT(6)
> +#define DMA_AXI_BLEN64			BIT(5)
> +#define DMA_AXI_BLEN32			BIT(4)
> +#define DMA_AXI_BLEN16			BIT(3)
> +#define DMA_AXI_BLEN8			BIT(2)
> +#define DMA_AXI_BLEN4			BIT(1)
> +#define DMA_BURST_LEN_DEFAULT		(DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
> +					 DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
> +					 DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
> +					 DMA_AXI_BLEN4)
> +
> +#define DMA_AXI_UNDEF			BIT(0)
> +
> +#define DMA_AXI_BURST_LEN_MASK		0x000000fe
> +
> +#define DMA_CUR_TX_BUF_ADDR		0x00001050	/* Current Host Tx Buffer */
> +#define DMA_CUR_RX_BUF_ADDR		0x00001054	/* Current Host Rx Buffer */
> +#define DMA_HW_FEATURE			0x00001058	/* HW Feature Register */
> +
> +/* DMA Control register defines */
> +#define DMA_CONTROL_ST			0x00002000	/* Start/Stop Transmission */
> +#define DMA_CONTROL_SR			0x00000002	/* Start/Stop Receive */
> +
> +/* DMA Normal interrupt */
> +#define DMA_INTR_ENA_NIE		0x00060000	/* Normal Summary */
> +#define DMA_INTR_ENA_TIE		0x00000001	/* Transmit Interrupt */
> +#define DMA_INTR_ENA_TUE		0x00000004	/* Transmit Buffer Unavailable */
> +#define DMA_INTR_ENA_RIE		0x00000040	/* Receive Interrupt */
> +#define DMA_INTR_ENA_ERE		0x00004000	/* Early Receive */
> +
> +#define DMA_INTR_NORMAL			(DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
> +					 DMA_INTR_ENA_TIE)
> +
> +/* DMA Abnormal interrupt */
> +#define DMA_INTR_ENA_AIE		0x00018000	/* Abnormal Summary */
> +#define DMA_INTR_ENA_FBE		0x00002000	/* Fatal Bus Error */
> +#define DMA_INTR_ENA_ETE		0x00000400	/* Early Transmit */
> +#define DMA_INTR_ENA_RWE		0x00000200	/* Receive Watchdog */
> +#define DMA_INTR_ENA_RSE		0x00000100	/* Receive Stopped */
> +#define DMA_INTR_ENA_RUE		0x00000080	/* Receive Buffer Unavailable */
> +#define DMA_INTR_ENA_UNE		0x00000020	/* Tx Underflow */
> +#define DMA_INTR_ENA_OVE		0x00000010	/* Receive Overflow */
> +#define DMA_INTR_ENA_TJE		0x00000008	/* Transmit Jabber */
> +#define DMA_INTR_ENA_TSE		0x00000002	/* Transmit Stopped */
> +
> +#define DMA_INTR_ABNORMAL		(DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
> +					 DMA_INTR_ENA_UNE)
> +
> +/* DMA default interrupt mask */
> +#define DMA_INTR_DEFAULT_MASK		(DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
> +#define DMA_INTR_DEFAULT_RX		(DMA_INTR_ENA_RIE)
> +#define DMA_INTR_DEFAULT_TX		(DMA_INTR_ENA_TIE)
> +
> +/* DMA Status register defines */
> +#define DMA_STATUS_GLPII		0x10000000	/* GMAC LPI interrupt */
> +#define DMA_STATUS_EB_MASK		0x0e000000	/* Error Bits Mask */
> +#define DMA_STATUS_EB_TX_ABORT		0x00080000	/* Error Bits - TX Abort */
> +#define DMA_STATUS_EB_RX_ABORT		0x00100000	/* Error Bits - RX Abort */
> +#define DMA_STATUS_TS_MASK		0x01c00000	/* Transmit Process State */
> +#define DMA_STATUS_TS_SHIFT		22
> +#define DMA_STATUS_RS_MASK		0x00380000	/* Receive Process State */
> +#define DMA_STATUS_RS_SHIFT		19
> +#define DMA_STATUS_TX_NIS		0x00040000	/* Normal Tx Interrupt Summary */
> +#define DMA_STATUS_RX_NIS		0x00020000	/* Normal Rx Interrupt Summary */
> +#define DMA_STATUS_TX_AIS		0x00010000	/* Abnormal Tx Interrupt Summary */
> +#define DMA_STATUS_RX_AIS		0x00008000	/* Abnormal Rx Interrupt Summary */
> +#define DMA_STATUS_ERI			0x00004000	/* Early Receive Interrupt */
> +#define DMA_STATUS_TX_FBI		0x00002000	/* Fatal Tx Bus Error Interrupt */
> +#define DMA_STATUS_RX_FBI		0x00001000	/* Fatal Rx Bus Error Interrupt */
> +#define DMA_STATUS_ETI			0x00000400	/* Early Transmit Interrupt */
> +#define DMA_STATUS_RWT			0x00000200	/* Receive Watchdog Timeout */
> +#define DMA_STATUS_RPS			0x00000100	/* Receive Process Stopped */
> +#define DMA_STATUS_RU			0x00000080	/* Receive Buffer Unavailable */
> +#define DMA_STATUS_RI			0x00000040	/* Receive Interrupt */
> +#define DMA_STATUS_UNF			0x00000020	/* Transmit Underflow */
> +#define DMA_STATUS_OVF			0x00000010	/* Receive Overflow */
> +#define DMA_STATUS_TJT			0x00000008	/* Transmit Jabber Timeout */
> +#define DMA_STATUS_TU			0x00000004	/* Transmit Buffer Unavailable */
> +#define DMA_STATUS_TPS			0x00000002	/* Transmit Process Stopped */
> +#define DMA_STATUS_TI			0x00000001	/* Transmit Interrupt */
> +#define DMA_CONTROL_FTF			0x00100000	/* Flush transmit FIFO */
> +
> +#define DMA_STATUS_MSK_RX_COMMON	(DMA_STATUS_RX_NIS | \
> +					 DMA_STATUS_RX_AIS | \
> +					 DMA_STATUS_RX_FBI)
> +
> +#define DMA_STATUS_MSK_TX_COMMON	(DMA_STATUS_TX_NIS | \
> +					 DMA_STATUS_TX_AIS | \
> +					 DMA_STATUS_TX_FBI)
> +
> +#define DMA_STATUS_MSK_RX		(DMA_STATUS_ERI | \
> +					 DMA_STATUS_RWT | \
> +					 DMA_STATUS_RPS | \
> +					 DMA_STATUS_RU | \
> +					 DMA_STATUS_RI | \
> +					 DMA_STATUS_OVF | \
> +					 DMA_STATUS_MSK_RX_COMMON)
> +
> +#define DMA_STATUS_MSK_TX		(DMA_STATUS_ETI | \
> +					 DMA_STATUS_UNF | \
> +					 DMA_STATUS_TJT | \
> +					 DMA_STATUS_TU | \
> +					 DMA_STATUS_TPS | \
> +					 DMA_STATUS_TI | \
> +					 DMA_STATUS_MSK_TX_COMMON)
> +
> +/* Following DMA defines are chanels oriented */
> +#define DMA_CHAN_OFFSET			0x100
> +
> +static inline u32 dma_chan_base_addr(u32 base, u32 chan)
> +{
> +	return base + chan * DMA_CHAN_OFFSET;
> +}
> +
> +#define DMA_CHAN_NEWFUNC_CONFIG(chan)	dma_chan_base_addr(DMA_NEWFUNC_CONFIG, chan)
> +#define DMA_CHAN_XMT_POLL_DEMAND(chan)	dma_chan_base_addr(DMA_XMT_POLL_DEMAND, chan)
> +#define DMA_CHAN_INTR_ENA(chan)		dma_chan_base_addr(DMA_INTR_ENA, chan)
> +#define DMA_CHAN_CONTROL(chan)		dma_chan_base_addr(DMA_CONTROL, chan)
> +#define DMA_CHAN_STATUS(chan)		dma_chan_base_addr(DMA_STATUS, chan)
> +#define DMA_CHAN_BUS_MODE(chan)		dma_chan_base_addr(DMA_BUS_MODE, chan)
> +#define DMA_CHAN_RCV_BASE_ADDR(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR, chan)
> +#define DMA_CHAN_RCV_BASE_ADDR64(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR64, chan)
> +#define DMA_CHAN_RCV_BASE_ADDR64_HI(chan)	dma_chan_base_addr(DMA_RCV_BASE_ADDR64_HI, chan)
> +#define DMA_CHAN_TX_BASE_ADDR(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR, chan)
> +#define DMA_CHAN_TX_BASE_ADDR64(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR64, chan)
> +#define DMA_CHAN_TX_BASE_ADDR64_HI(chan)	dma_chan_base_addr(DMA_TX_BASE_ADDR64_HI, chan)
> +#define DMA_CHAN_RX_WATCHDOG(chan)	dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
> +
> +#define NUM_DWEGMAC_DMA_REGS	23
> +
> +#endif /* __DWEGMAC_DMA_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> index c5768bbec38e..4674af3d78cb 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> @@ -61,7 +61,7 @@ static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
>  		dev_info(priv->device, "Enhanced/Alternate descriptors\n");
>  
>  		/* GMAC older than 3.50 has no extended descriptors */
> -		if (priv->synopsys_id >= DWMAC_CORE_3_50) {
> +		if (priv->synopsys_id >= DWMAC_CORE_3_50 || priv->plat->has_egmac) {
>  			dev_info(priv->device, "Enabled extended descriptors\n");
>  			priv->extend_desc = 1;
>  		} else {
> @@ -107,6 +107,7 @@ static const struct stmmac_hwif_entry {
>  	bool gmac;
>  	bool gmac4;
>  	bool xgmac;
> +	bool egmac;
>  	u32 min_id;
>  	u32 dev_id;
>  	const struct stmmac_regs_off regs;
> @@ -125,6 +126,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = false,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = 0,
>  		.regs = {
>  			.ptp_off = PTP_GMAC3_X_OFFSET,
> @@ -143,6 +145,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = true,
>  		.gmac4 = false,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = 0,
>  		.regs = {
>  			.ptp_off = PTP_GMAC3_X_OFFSET,
> @@ -161,6 +164,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = true,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = 0,
>  		.regs = {
>  			.ptp_off = PTP_GMAC4_OFFSET,
> @@ -179,6 +183,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = true,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = DWMAC_CORE_4_00,
>  		.regs = {
>  			.ptp_off = PTP_GMAC4_OFFSET,
> @@ -197,6 +202,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = true,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = DWMAC_CORE_4_10,
>  		.regs = {
>  			.ptp_off = PTP_GMAC4_OFFSET,
> @@ -215,6 +221,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = true,
>  		.xgmac = false,
> +		.egmac = false,
>  		.min_id = DWMAC_CORE_5_10,
>  		.regs = {
>  			.ptp_off = PTP_GMAC4_OFFSET,
> @@ -233,6 +240,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = false,
>  		.xgmac = true,
> +		.egmac = false,
>  		.min_id = DWXGMAC_CORE_2_10,
>  		.dev_id = DWXGMAC_ID,
>  		.regs = {
> @@ -252,6 +260,7 @@ static const struct stmmac_hwif_entry {
>  		.gmac = false,
>  		.gmac4 = false,
>  		.xgmac = true,
> +		.egmac = false,
>  		.min_id = DWXLGMAC_CORE_2_00,
>  		.dev_id = DWXLGMAC_ID,
>  		.regs = {
> @@ -267,11 +276,50 @@ static const struct stmmac_hwif_entry {
>  		.mmc = &dwxgmac_mmc_ops,
>  		.setup = dwxlgmac2_setup,
>  		.quirks = stmmac_dwxlgmac_quirks,
> +	}, {
> +		.gmac = false,
> +		.gmac4 = false,
> +		.xgmac = false,
> +		.egmac = true,
> +		.min_id = DWEGMAC_CORE_1_00,
> +		.regs = {
> +			.ptp_off = PTP_GMAC3_X_OFFSET,
> +			.mmc_off = MMC_GMAC3_X_OFFSET,
> +		},
> +		.desc = NULL,
> +		.dma = &dwegmac_dma_ops,
> +		.mac = &dwegmac_ops,
> +		.hwtimestamp = &stmmac_ptp,
> +		.mode = NULL,
> +		.tc = NULL,
> +		.mmc = &dwmac_mmc_ops,
> +		.setup = dwegmac_setup,
> +		.quirks = stmmac_dwmac1_quirks,
> +	}, {
> +		.gmac = false,
> +		.gmac4 = false,
> +		.xgmac = false,
> +		.egmac = true,
> +		.min_id = DWMAC_CORE_3_50,
> +		.regs = {
> +			.ptp_off = PTP_GMAC3_X_OFFSET,
> +			.mmc_off = MMC_GMAC3_X_OFFSET,
> +		},
> +		.desc = NULL,
> +		.dma = &dwmac1000_dma_ops,
> +		.mac = &dwmac1000_ops,
> +		.hwtimestamp = &stmmac_ptp,
> +		.mode = NULL,
> +		.tc = NULL,
> +		.mmc = &dwmac_mmc_ops,
> +		.setup = dwmac1000_setup,
> +		.quirks = stmmac_dwmac1_quirks,
>  	},
>  };
>  
>  int stmmac_hwif_init(struct stmmac_priv *priv)
>  {
> +	bool needs_egmac = priv->plat->has_egmac;
>  	bool needs_xgmac = priv->plat->has_xgmac;
>  	bool needs_gmac4 = priv->plat->has_gmac4;
>  	bool needs_gmac = priv->plat->has_gmac;
> @@ -281,7 +329,7 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
>  	u32 id, dev_id = 0;
>  	int i, ret;
>  
> -	if (needs_gmac) {
> +	if (needs_gmac || needs_egmac) {
>  		id = stmmac_get_id(priv, GMAC_VERSION);
>  	} else if (needs_gmac4 || needs_xgmac) {
>  		id = stmmac_get_id(priv, GMAC4_VERSION);
> @@ -321,6 +369,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
>  			continue;
>  		if (needs_xgmac ^ entry->xgmac)
>  			continue;
> +		if (needs_egmac ^ entry->egmac)
> +			continue;
>  		/* Use synopsys_id var because some setups can override this */
>  		if (priv->synopsys_id < entry->min_id)
>  			continue;
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> index 00be9a7003c8..41989903e8c9 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> @@ -667,6 +667,8 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
>  extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
>  extern const struct stmmac_mmc_ops dwmac_mmc_ops;
>  extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
> +extern const struct stmmac_ops dwegmac_ops;
> +extern const struct stmmac_dma_ops dwegmac_dma_ops;
>  
>  #define GMAC_VERSION		0x00000020	/* GMAC CORE Version */
>  #define GMAC4_VERSION		0x00000110	/* GMAC4+ CORE Version */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> index 2ae73ab842d4..dba33ce392a8 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> @@ -596,7 +596,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
>  				priv->xstats.phy_eee_wakeup_error_n = val;
>  		}
>  
> -		if (priv->synopsys_id >= DWMAC_CORE_3_50)
> +		if (priv->synopsys_id >= DWMAC_CORE_3_50 || priv->plat->has_egmac)
>  			stmmac_mac_debug(priv, priv->ioaddr,
>  					(void *)&priv->xstats,
>  					rx_queues_count, tx_queues_count);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index e8619853b6d6..f91dd3f69fef 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -6936,7 +6936,8 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
>  	 * riwt_off field from the platform.
>  	 */
>  	if (((priv->synopsys_id >= DWMAC_CORE_3_50) ||
> -	    (priv->plat->has_xgmac)) && (!priv->plat->riwt_off)) {
> +	    (priv->plat->has_xgmac) || (priv->plat->has_egmac)) &&
> +	    (!priv->plat->riwt_off)) {
>  		priv->use_riwt = 1;
>  		dev_info(priv->device,
>  			 "Enable RX Mitigation via HW Watchdog Timer\n");
> diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
> index 2fcd83f6db14..0e36259a9568 100644
> --- a/include/linux/stmmac.h
> +++ b/include/linux/stmmac.h
> @@ -295,5 +295,6 @@ struct plat_stmmacenet_data {
>  	bool serdes_up_after_phy_linkup;
>  	const struct dwmac4_addrs *dwmac4_addrs;
>  	bool has_integrated_pcs;
> +	int has_egmac;
>  };
>  #endif
> -- 
> 2.39.3
> 
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v4 00/11] stmmac: Add Loongson platform support
  2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
                   ` (10 preceding siblings ...)
  2023-08-22  9:41 ` [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support Feiyang Chen
@ 2023-08-24  1:47 ` Feiyang Chen
  11 siblings, 0 replies; 16+ messages in thread
From: Feiyang Chen @ 2023-08-24  1:47 UTC (permalink / raw)
  To: Feiyang Chen
  Cc: andrew, hkallweit1, peppe.cavallaro, alexandre.torgue, joabreu,
	chenhuacai, linux, dongbiao, guyinggang, siyanteng,
	loongson-kernel, netdev, loongarch

On Tue, Aug 22, 2023 at 5:40 PM Feiyang Chen <chenfeiyang@loongson.cn> wrote:
>
> Add and extend stmmac functions and macros for Loongson DWMAC.
> Add LS7A support and GNET support for dwmac_loongson.
>
> Split the code for extended GMAC (dwegmac) from dwmac1000, try
> not to mix up registers and core id.
>
> Some features of Loongson platforms are bound to the GMAC_VERSION
> register. We have to read its value in dwmac-loongson in order to
> get the correct channel number and DMA configuration.
>
> The current usage of stmmac_request_irq_multi_msi() is limited to
> dwmac-intel. While it appears that setting irq_flags might not be
> necessary for dwmac-intel, it should be configured for other drivers
> like dwmac-loongson. I've observed many drivers directly setting
> irq_flags within their probe functions or data structures without
> referencing the DT. Since I'm unsure about the proper handling of
> irq_flags, I've chosen to retain the code as-is.
>
> Feiyang Chen (11):
>   net: stmmac: Pass stmmac_priv and chan in some callbacks
>   stmmac: dwmac1000: Add 64-bit DMA support
>   stmmac: Add extended GMAC support for Loongson platforms
>   net: stmmac: Allow platforms to set irq_flags
>   net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe()
>   net: stmmac: dwmac-loongson: Add LS7A support
>   net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support
>   net: stmmac: dwegmac: Fix channel numbers
>   net: stmmac: dwmac-loongson: Disable flow control for GMAC
>   net: stmmac: dwegmac: Disable coe
>   net: stmmac: dwmac-loongson: Add GNET support
>
>  drivers/net/ethernet/stmicro/stmmac/Makefile  |   2 +-
>  .../net/ethernet/stmicro/stmmac/chain_mode.c  |  29 +-
>  drivers/net/ethernet/stmicro/stmmac/common.h  |   3 +
>  drivers/net/ethernet/stmicro/stmmac/descs.h   |   7 +
>  .../net/ethernet/stmicro/stmmac/descs_com.h   |  47 +-
>  drivers/net/ethernet/stmicro/stmmac/dwegmac.h | 332 +++++++++++
>  .../ethernet/stmicro/stmmac/dwegmac_core.c    | 552 ++++++++++++++++++
>  .../net/ethernet/stmicro/stmmac/dwegmac_dma.c | 522 +++++++++++++++++
>  .../net/ethernet/stmicro/stmmac/dwegmac_dma.h | 190 ++++++
>  .../ethernet/stmicro/stmmac/dwmac-loongson.c  | 338 ++++++++---
>  .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c |  22 +-
>  .../ethernet/stmicro/stmmac/dwmac1000_core.c  |   9 +-
>  .../ethernet/stmicro/stmmac/dwmac1000_dma.c   |  54 +-
>  .../ethernet/stmicro/stmmac/dwmac100_core.c   |   9 +-
>  .../ethernet/stmicro/stmmac/dwmac100_dma.c    |   2 +-
>  .../net/ethernet/stmicro/stmmac/dwmac4_core.c |  11 +-
>  .../ethernet/stmicro/stmmac/dwmac4_descs.c    |  17 +-
>  .../net/ethernet/stmicro/stmmac/dwmac4_dma.c  |   8 +-
>  .../net/ethernet/stmicro/stmmac/dwmac4_dma.h  |   2 +-
>  .../net/ethernet/stmicro/stmmac/dwmac4_lib.c  |   2 +-
>  .../net/ethernet/stmicro/stmmac/dwmac_dma.h   |  22 +-
>  .../net/ethernet/stmicro/stmmac/dwmac_lib.c   |   5 +-
>  .../ethernet/stmicro/stmmac/dwxgmac2_core.c   |  11 +-
>  .../ethernet/stmicro/stmmac/dwxgmac2_descs.c  |  17 +-
>  .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    |  10 +-
>  .../net/ethernet/stmicro/stmmac/enh_desc.c    |  38 +-
>  drivers/net/ethernet/stmicro/stmmac/hwif.c    |  66 ++-
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  73 ++-
>  .../net/ethernet/stmicro/stmmac/norm_desc.c   |  17 +-
>  .../net/ethernet/stmicro/stmmac/ring_mode64.c | 158 +++++
>  .../ethernet/stmicro/stmmac/stmmac_ethtool.c  |   8 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c |  34 +-
>  include/linux/stmmac.h                        |  11 +
>  33 files changed, 2410 insertions(+), 218 deletions(-)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac.h
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_core.c
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.c
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwegmac_dma.h
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode64.c
>
> --
> 2.39.3
>

Due to some recent work adjustments, Yanteng will be taking over the
patch series.

Thanks,
Feiyang

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-08-24  1:48 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-22  9:40 [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen
2023-08-22  9:40 ` [PATCH v4 01/11] net: stmmac: Pass stmmac_priv and chan in some callbacks Feiyang Chen
2023-08-22 10:03   ` Russell King (Oracle)
2023-08-22  9:40 ` [PATCH v4 02/11] stmmac: dwmac1000: Add 64-bit DMA support Feiyang Chen
2023-08-22  9:40 ` [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson platforms Feiyang Chen
2023-08-22 16:13   ` Serge Semin
2023-08-22  9:40 ` [PATCH v4 04/11] net: stmmac: Allow platforms to set irq_flags Feiyang Chen
2023-08-22  9:40 ` [PATCH v4 05/11] net: stmmac: dwmac-loongson: Refactor code for loongson_dwmac_probe() Feiyang Chen
2023-08-22  9:40 ` [PATCH v4 06/11] net: stmmac: dwmac-loongson: Add LS7A support Feiyang Chen
2023-08-22  9:40 ` [PATCH v4 07/11] net: stmmac: dwmac-loongson: Add 64-bit DMA and MSI support Feiyang Chen
2023-08-22  9:41 ` [PATCH v4 08/11] net: stmmac: dwegmac: Fix channel numbers Feiyang Chen
2023-08-22  9:41 ` [PATCH v4 09/11] net: stmmac: dwmac-loongson: Disable flow control for GMAC Feiyang Chen
2023-08-22  9:41 ` [PATCH v4 10/11] net: stmmac: dwegmac: Disable coe Feiyang Chen
2023-08-22  9:41 ` [PATCH v4 11/11] net: stmmac: dwmac-loongson: Add GNET support Feiyang Chen
2023-08-22 11:45   ` Russell King (Oracle)
2023-08-24  1:47 ` [PATCH v4 00/11] stmmac: Add Loongson platform support Feiyang Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).