[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <36keczymn6bjlsgf6u3xgf52jt3is3qzh64dv4tro35mrmrsz4@l5j3ld55fojd>
Date: Tue, 22 Aug 2023 19:13:37 +0300
From: Serge Semin <fancer.lancer@...il.com>
To: Feiyang Chen <chenfeiyang@...ngson.cn>, andrew@...n.ch,
Russell King <linux@...linux.org.uk>
Cc: hkallweit1@...il.com, peppe.cavallaro@...com,
alexandre.torgue@...s.st.com, joabreu@...opsys.com, chenhuacai@...ngson.cn,
dongbiao@...ngson.cn, guyinggang@...ngson.cn, siyanteng@...ngson.cn,
loongson-kernel@...ts.loongnix.cn, netdev@...r.kernel.org, loongarch@...ts.linux.dev,
chris.chenfeiyang@...il.com
Subject: Re: [PATCH v4 03/11] stmmac: Add extended GMAC support for Loongson
platforms
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@...ngson.cn>
> Signed-off-by: Yinggang Gu <guyinggang@...ngson.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
>
>
Powered by blists - more mailing lists