[PATCH v10 1/3] net/macb: add new poll mode driver

Ivan Malov ivan.malov at arknetworks.am
Wed Aug 20 11:33:07 CEST 2025


Hi,

(please see below)

On Wed, 20 Aug 2025, Wencheng Li wrote:

> Add MACB PMD driver for Phytium NIC.
>
> v10:
> - Removed unused spinlock from base/macb_common.h.
> - Renamed symbols to avoid name conflicts.
> - Fixed some code style issues.
>
> Signed-off-by: Wencheng Li <liwencheng at phytium.com.cn>
> ---
> .mailmap                            |    1 +
> drivers/net/macb/base/generic_phy.c |  271 ++++++
> drivers/net/macb/base/generic_phy.h |  195 ++++
> drivers/net/macb/base/macb_common.c |  650 +++++++++++++
> drivers/net/macb/base/macb_common.h |  251 +++++
> drivers/net/macb/base/macb_errno.h  |   58 ++
> drivers/net/macb/base/macb_hw.h     | 1138 +++++++++++++++++++++++
> drivers/net/macb/base/macb_type.h   |   23 +
> drivers/net/macb/base/macb_uio.c    |  351 +++++++
> drivers/net/macb/base/macb_uio.h    |   50 +
> drivers/net/macb/base/meson.build   |   25 +
> drivers/net/macb/macb_ethdev.c      | 1755 +++++++++++++++++++++++++++++++++++
> drivers/net/macb/macb_ethdev.h      |   75 ++
> drivers/net/macb/macb_log.h         |   19 +
> drivers/net/macb/macb_rxtx.c        | 1391 +++++++++++++++++++++++++++
> drivers/net/macb/macb_rxtx.h        |  325 +++++++
> drivers/net/macb/meson.build        |   18 +
> drivers/net/meson.build             |    1 +
> 18 files changed, 6597 insertions(+)
> create mode 100644 drivers/net/macb/base/generic_phy.c
> create mode 100644 drivers/net/macb/base/generic_phy.h
> create mode 100644 drivers/net/macb/base/macb_common.c
> create mode 100644 drivers/net/macb/base/macb_common.h
> create mode 100644 drivers/net/macb/base/macb_errno.h
> create mode 100644 drivers/net/macb/base/macb_hw.h
> create mode 100644 drivers/net/macb/base/macb_type.h
> create mode 100644 drivers/net/macb/base/macb_uio.c
> create mode 100644 drivers/net/macb/base/macb_uio.h
> create mode 100644 drivers/net/macb/base/meson.build
> create mode 100644 drivers/net/macb/macb_ethdev.c
> create mode 100644 drivers/net/macb/macb_ethdev.h
> create mode 100644 drivers/net/macb/macb_log.h
> create mode 100644 drivers/net/macb/macb_rxtx.c
> create mode 100644 drivers/net/macb/macb_rxtx.h
> create mode 100644 drivers/net/macb/meson.build
>
> diff --git a/.mailmap b/.mailmap
> index 34a99f9..f671d50 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -1728,6 +1728,7 @@ Wen-Chi Yang <wolkayang at gmail.com>
> Wenfeng Liu <liuwf at arraynetworks.com.cn>
> Wenjie Li <wenjiex.a.li at intel.com>
> Wenjie Sun <findtheonlyway at gmail.com>
> +Wencheng Li <liwencheng at phytium.com.cn>
> Wenjing Qiao <wenjing.qiao at intel.com>
> Wenjun Wu <wenjun1.wu at intel.com>
> Wentao Cui <wentaoc at mellanox.com>
> diff --git a/drivers/net/macb/base/generic_phy.c b/drivers/net/macb/base/generic_phy.c
> new file mode 100644
> index 0000000..815f9a5
> --- /dev/null
> +++ b/drivers/net/macb/base/generic_phy.c
> @@ -0,0 +1,271 @@
> +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.

Why 2022? Same question applies to multiple other places in this patch.

> + */
> +
> +#include "generic_phy.h"
> +#include "macb_hw.h"
> +
> +static uint32_t genphy_get_an(struct macb *bp, uint16_t phyad, u16 addr)
> +{
> +	int advert;
> +
> +	advert = macb_mdio_read(bp, phyad, addr);
> +
> +	return genphy_lpa_to_ethtool_lpa_t(advert);
> +}
> +
> +static int phy_poll_reset(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint32_t retries = 12;
> +	int32_t ret;
> +	uint16_t phyad = phydev->phyad;
> +
> +	do {
> +		rte_delay_ms(50);
> +		ret = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +		if (ret < 0)
> +			return ret;
> +	} while (ret & BMCR_RESET && --retries);
> +	if (ret & BMCR_RESET)
> +		return -ETIMEDOUT;
> +
> +	rte_delay_ms(1);
> +	return 0;
> +}
> +
> +static int genphy_soft_reset(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint32_t ctrl;
> +	uint16_t phyad = phydev->phyad;
> +
> +	/* soft reset phy */
> +	ctrl = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +	ctrl |= BMCR_RESET;
> +	macb_mdio_write(bp, phyad, GENERIC_PHY_BMCR, ctrl);
> +
> +	return phy_poll_reset(phydev);
> +}
> +
> +static int genphy_resume(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint32_t ctrl;
> +	uint16_t phyad = phydev->phyad;
> +
> +	/* phy power up */
> +	ctrl = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +	ctrl &= ~BMCR_PDOWN;
> +	macb_mdio_write(bp, phyad, GENERIC_PHY_BMCR, ctrl);
> +	rte_delay_ms(100);
> +	return 0;
> +}
> +
> +static void genphy_suspend(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint32_t ctrl;
> +	uint16_t phyad = phydev->phyad;
> +
> +	/* phy power down */
> +	ctrl = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +	ctrl |= BMCR_PDOWN;
> +	macb_mdio_write(bp, phyad, GENERIC_PHY_BMCR, ctrl);
> +}
> +
> +static int genphy_force_speed_duplex(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint32_t ctrl;
> +	uint16_t phyad = phydev->phyad;
> +
> +	if (bp->autoneg) {
> +		ctrl = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +		ctrl |= BMCR_ANENABLE;
> +		macb_mdio_write(bp, phyad, GENERIC_PHY_BMCR, ctrl);
> +		rte_delay_ms(10);
> +	} else {
> +		/* disable autoneg first */
> +		ctrl = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +		ctrl &= ~BMCR_ANENABLE;
> +
> +		if (bp->duplex == DUPLEX_FULL)
> +			ctrl |= BMCR_FULLDPLX;
> +		else
> +			ctrl &= ~BMCR_FULLDPLX;
> +
> +		switch (bp->speed) {
> +		case SPEED_10:
> +			ctrl &= ~BMCR_SPEED1000;
> +			ctrl &= ~BMCR_SPEED100;
> +			break;
> +		case SPEED_100:
> +			ctrl |= BMCR_SPEED100;
> +			ctrl &= ~BMCR_SPEED1000;
> +			break;
> +		case SPEED_1000:
> +			ctrl |= BMCR_ANENABLE;
> +			bp->autoneg = AUTONEG_ENABLE;
> +			break;
> +		case SPEED_2500:
> +			ctrl |= BMCR_ANENABLE;
> +			bp->autoneg = AUTONEG_ENABLE;
> +			break;
> +		}
> +		macb_mdio_write(bp, phyad, GENERIC_PHY_BMCR, ctrl);
> +		phydev->autoneg = bp->autoneg;
> +		rte_delay_ms(10);
> +	}
> +
> +	return 0;
> +}
> +
> +static int genphy_check_for_link(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	int bmsr;
> +
> +	/* Do a fake read */
> +	bmsr = macb_mdio_read(bp, bp->phyad, GENERIC_PHY_BMSR);
> +	if (bmsr < 0)
> +		return bmsr;
> +
> +	bmsr = macb_mdio_read(bp, bp->phyad, GENERIC_PHY_BMSR);
> +	phydev->link = bmsr & BMSR_LSTATUS;
> +
> +	return phydev->link;
> +}
> +
> +static int genphy_read_status(struct phy_device *phydev)
> +{
> +	struct macb *bp = phydev->bp;
> +	uint16_t bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
> +	uint32_t advertising, lp_advertising;
> +	uint32_t nego;
> +	uint16_t phyad = phydev->phyad;
> +
> +	/* Do a fake read */
> +	bmsr = macb_mdio_read(bp, phyad, GENERIC_PHY_BMSR);
> +
> +	bmsr = macb_mdio_read(bp, phyad, GENERIC_PHY_BMSR);
> +	bmcr = macb_mdio_read(bp, phyad, GENERIC_PHY_BMCR);
> +
> +	if (bmcr & BMCR_ANENABLE) {
> +		ctrl1000 = macb_mdio_read(bp, phyad, GENERIC_PHY_CTRL1000);
> +		stat1000 = macb_mdio_read(bp, phyad, GENERIC_PHY_STAT1000);
> +
> +		advertising = ADVERTISED_Autoneg;
> +		advertising |= genphy_get_an(bp, phyad, GENERIC_PHY_ADVERISE);
> +		advertising |= genphy_ctrl1000_to_ethtool_adv_t(ctrl1000);
> +
> +		if (bmsr & BMSR_ANEGCOMPLETE) {
> +			lp_advertising = genphy_get_an(bp, phyad, GENERIC_PHY_LPA);
> +			lp_advertising |= genphy_stat1000_to_ethtool_lpa_t(stat1000);
> +		} else {
> +			lp_advertising = 0;
> +		}
> +
> +		nego = advertising & lp_advertising;
> +		if (nego & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half)) {
> +			phydev->speed = SPEED_1000;
> +			phydev->duplex = !!(nego & ADVERTISED_1000baseT_Full);
> +		} else if (nego &
> +				(ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) {
> +			phydev->speed = SPEED_100;
> +			phydev->duplex = !!(nego & ADVERTISED_100baseT_Full);
> +		} else {
> +			phydev->speed = SPEED_10;
> +			phydev->duplex = !!(nego & ADVERTISED_10baseT_Full);
> +		}
> +	} else {
> +		phydev->speed = ((bmcr & BMCR_SPEED1000 && (bmcr & BMCR_SPEED100) == 0)
> +						 ? SPEED_1000
> +						 : ((bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10));
> +		phydev->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
> +	}
> +
> +	return 0;
> +}
> +
> +int macb_usxgmii_pcs_resume(struct phy_device *phydev)
> +{
> +	u32 config;
> +	struct macb *bp = phydev->bp;
> +
> +	config = gem_readl(bp, USX_CONTROL);
> +
> +	/* enable signal */
> +	config &= ~(GEM_BIT(RX_SYNC_RESET));
> +	config |= GEM_BIT(SIGNAL_OK) | GEM_BIT(TX_EN);
> +	gem_writel(bp, USX_CONTROL, config);
> +
> +	return 0;
> +}
> +
> +void macb_usxgmii_pcs_suspend(struct phy_device *phydev)
> +{
> +	uint32_t config;
> +	struct macb *bp = phydev->bp;
> +
> +	config = gem_readl(bp, USX_CONTROL);
> +	config |= GEM_BIT(RX_SYNC_RESET);
> +	/* disable signal */
> +	config &= ~(GEM_BIT(SIGNAL_OK) | GEM_BIT(TX_EN));
> +	gem_writel(bp, USX_CONTROL, config);
> +	rte_delay_ms(1);
> +}
> +
> +int macb_usxgmii_pcs_check_for_link(struct phy_device *phydev)
> +{
> +	int link;
> +	struct macb *bp = phydev->bp;
> +
> +	link = (int)GEM_BFEXT(BLOCK_LOCK, gem_readl(bp, USX_STATUS));
> +	return link;
> +}
> +
> +int macb_gbe_pcs_check_for_link(struct phy_device *phydev)
> +{
> +	int link;
> +	struct macb *bp = phydev->bp;
> +
> +	link = (int)MACB_BFEXT(NSR_LINK, macb_readl(bp, NSR));
> +	return link;
> +}
> +
> +const struct phy_driver genphy_driver = {
> +	.phy_id		= 0xffffffff,
> +	.phy_id_mask	= 0xffffffff,
> +	.name		= "Generic PHY",
> +	.soft_reset	= genphy_soft_reset,
> +	.suspend	= genphy_suspend,
> +	.resume		= genphy_resume,
> +	.check_for_link		= genphy_check_for_link,
> +	.read_status		= genphy_read_status,
> +	.force_speed_duplex = genphy_force_speed_duplex,
> +};
> +
> +const struct phy_driver macb_gbe_pcs_driver = {
> +	.phy_id		= 0xffffffff,
> +	.phy_id_mask	= 0xffffffff,
> +	.name		= "Macb gbe pcs PHY",
> +	.soft_reset	= NULL,
> +	.suspend	= NULL,
> +	.resume		= NULL,
> +	.check_for_link		= macb_gbe_pcs_check_for_link,
> +	.read_status		= NULL,
> +	.force_speed_duplex = NULL,
> +};
> +
> +const struct phy_driver macb_usxgmii_pcs_driver = {
> +	.phy_id		= 0xffffffff,
> +	.phy_id_mask	= 0xffffffff,
> +	.name		= "Macb usxgmii pcs PHY",
> +	.soft_reset	= NULL,
> +	.suspend	= macb_usxgmii_pcs_suspend,
> +	.resume		= macb_usxgmii_pcs_resume,
> +	.check_for_link		= macb_usxgmii_pcs_check_for_link,
> +	.read_status		= NULL,
> +	.force_speed_duplex = NULL,
> +};
> diff --git a/drivers/net/macb/base/generic_phy.h b/drivers/net/macb/base/generic_phy.h
> new file mode 100644
> index 0000000..fdf004b
> --- /dev/null
> +++ b/drivers/net/macb/base/generic_phy.h
> @@ -0,0 +1,195 @@
> +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _GENERIC_PHY_H
> +#define _GENERIC_PHY_H
> +
> +#include "macb_common.h"
> +
> +/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
> + * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
> + */
> +#define MII_ADDR_C45		(1 << 30)
> +#define MII_DEVADDR_C45_SHIFT	16
> +#define MII_REGADDR_C45_MASK	0xffff
> +
> +/* Generic MII registers. */
> +#define GENERIC_PHY_BMCR            0x0
> +#define GENERIC_PHY_BMSR            0x1
> +#define GENERIC_PHY_PHYSID1         0x2
> +#define GENERIC_PHY_PHYSID2         0x3
> +#define GENERIC_PHY_ADVERISE        0x4
> +#define GENERIC_PHY_LPA				0x5
> +#define GENERIC_PHY_CTRL1000        0x9
> +#define GENERIC_PHY_STAT1000		0xa
> +
> +/* Basic mode control register. */
> +#define BMCR_RESV		0x003f	/* Unused...                   */
> +#define BMCR_SPEED1000		0x0040	/* MSB of Speed (1000)         */
> +#define BMCR_CTST		0x0080	/* Collision test              */
> +#define BMCR_FULLDPLX		0x0100	/* Full duplex                 */
> +#define BMCR_ANRESTART		0x0200	/* Auto negotiation restart    */
> +#define BMCR_ISOLATE		0x0400	/* Isolate data paths from MII */
> +#define BMCR_PDOWN		0x0800	/* Enable low power state      */
> +#define BMCR_ANENABLE		0x1000	/* Enable auto negotiation     */
> +#define BMCR_SPEED100		0x2000	/* Select 100Mbps              */
> +#define BMCR_LOOPBACK		0x4000	/* TXD loopback bits           */
> +#define BMCR_RESET		0x8000	/* Reset to default state      */
> +#define BMCR_SPEED10		0x0000	/* Select 10Mbps               */
> +
> +/* Basic mode status register. */
> +#define BMSR_ERCAP		0x0001	/* Ext-reg capability          */
> +#define BMSR_JCD		0x0002	/* Jabber detected             */
> +#define BMSR_LSTATUS		0x0004	/* Link status                 */
> +#define BMSR_ANEGCAPABLE	0x0008	/* Able to do auto-negotiation */
> +#define BMSR_RFAULT		0x0010	/* Remote fault detected       */
> +#define BMSR_ANEGCOMPLETE	0x0020	/* Auto-negotiation complete   */
> +#define BMSR_RESV		0x00c0	/* Unused...                   */
> +#define BMSR_ESTATEN		0x0100	/* Extended Status in R15      */
> +#define BMSR_100HALF2		0x0200	/* Can do 100BASE-T2 HDX       */
> +#define BMSR_100FULL2		0x0400	/* Can do 100BASE-T2 FDX       */
> +#define BMSR_10HALF		0x0800	/* Can do 10mbps, half-duplex  */
> +#define BMSR_10FULL		0x1000	/* Can do 10mbps, full-duplex  */
> +#define BMSR_100HALF		0x2000	/* Can do 100mbps, half-duplex */
> +#define BMSR_100FULL		0x4000	/* Can do 100mbps, full-duplex */
> +#define BMSR_100BASE4		0x8000	/* Can do 100mbps, 4k packets  */
> +
> +/* Advertisement control register. */
> +#define ADVERTISE_SLCT		0x001f	/* Selector bits               */
> +#define ADVERTISE_CSMA		0x0001	/* Only selector supported     */
> +#define ADVERTISE_10HALF	0x0020	/* Try for 10mbps half-duplex  */
> +#define ADVERTISE_1000XFULL	0x0020	/* Try for 1000BASE-X full-duplex */
> +#define ADVERTISE_10FULL	0x0040	/* Try for 10mbps full-duplex  */
> +#define ADVERTISE_1000XHALF	0x0040	/* Try for 1000BASE-X half-duplex */
> +#define ADVERTISE_100HALF	0x0080	/* Try for 100mbps half-duplex */
> +#define ADVERTISE_1000XPAUSE	0x0080	/* Try for 1000BASE-X pause    */
> +#define ADVERTISE_100FULL	0x0100	/* Try for 100mbps full-duplex */
> +#define ADVERTISE_1000XPSE_ASYM	0x0100	/* Try for 1000BASE-X asym pause */
> +#define ADVERTISE_100BASE4	0x0200	/* Try for 100mbps 4k packets  */
> +#define ADVERTISE_PAUSE_CAP	0x0400	/* Try for pause               */
> +#define ADVERTISE_PAUSE_ASYM	0x0800	/* Try for asymmetric pause     */
> +#define ADVERTISE_RESV		0x1000	/* Unused...                   */
> +#define ADVERTISE_RFAULT	0x2000	/* Say we can detect faults    */
> +#define ADVERTISE_LPACK		0x4000	/* Ack link partners response  */
> +#define ADVERTISE_NPAGE		0x8000	/* Next page bit               */
> +
> +/* Link partner ability register. */
> +#define LPA_SLCT		0x001f	/* Same as advertise selector  */
> +#define LPA_10HALF		0x0020	/* Can do 10mbps half-duplex   */
> +#define LPA_1000XFULL		0x0020	/* Can do 1000BASE-X full-duplex */
> +#define LPA_10FULL		0x0040	/* Can do 10mbps full-duplex   */
> +#define LPA_1000XHALF		0x0040	/* Can do 1000BASE-X half-duplex */
> +#define LPA_100HALF		0x0080	/* Can do 100mbps half-duplex  */
> +#define LPA_1000XPAUSE		0x0080	/* Can do 1000BASE-X pause     */
> +#define LPA_100FULL		0x0100	/* Can do 100mbps full-duplex  */
> +#define LPA_1000XPAUSE_ASYM	0x0100	/* Can do 1000BASE-X pause asym*/
> +#define LPA_100BASE4		0x0200	/* Can do 100mbps 4k packets   */
> +#define LPA_PAUSE_CAP		0x0400	/* Can pause                   */
> +#define LPA_PAUSE_ASYM		0x0800	/* Can pause asymmetrically     */
> +#define LPA_RESV		0x1000	/* Unused...                   */
> +#define LPA_RFAULT		0x2000	/* Link partner faulted        */
> +#define LPA_LPACK		0x4000	/* Link partner acked us       */
> +#define LPA_NPAGE		0x8000	/* Next page bit               */
> +
> +/* 1000BASE-T Control register */
> +#define ADVERTISE_1000FULL	0x0200  /* Advertise 1000BASE-T full duplex */
> +#define ADVERTISE_1000HALF	0x0100  /* Advertise 1000BASE-T half duplex */
> +#define CTL1000_AS_MASTER	0x0800
> +#define CTL1000_ENABLE_MASTER	0x1000
> +
> +/* 1000BASE-T Status register */
> +#define LPA_1000MSFAIL		0x8000	/* Primary/Secondary resolution failure */
> +#define LPA_1000LOCALRXOK	0x2000	/* Link partner local receiver status */
> +#define LPA_1000REMRXOK		0x1000	/* Link partner remote receiver status */
> +#define LPA_1000FULL		0x0800	/* Link partner 1000BASE-T full duplex */
> +#define LPA_1000HALF		0x0400	/* Link partner 1000BASE-T half duplex */
> +
> +struct phy_device {
> +	struct macb *bp;
> +	struct phy_driver *drv;
> +	uint32_t phy_id;
> +	uint16_t phyad;
> +	uint32_t speed;
> +	uint16_t link;
> +	uint16_t duplex;
> +	uint16_t autoneg;
> +	void *priv;
> +};
> +
> +struct phy_driver {
> +	const char *name;
> +	uint32_t phy_id;
> +	uint32_t phy_id_mask;
> +
> +	int (*config_init)(struct phy_device *phydev);
> +	int (*soft_reset)(struct phy_device *phydev);
> +	int (*probe)(struct phy_device *phydev);
> +	int (*resume)(struct phy_device *phydev);
> +	void (*suspend)(struct phy_device *phydev);
> +	int (*check_for_link)(struct phy_device *phydev);
> +	int (*read_status)(struct phy_device *phydev);
> +	int (*force_speed_duplex)(struct phy_device *phydev);
> +};
> +
> +static inline uint32_t genphy_adv_to_ethtool_adv_t(uint32_t adv)
> +{
> +	uint32_t result = 0;
> +
> +	if (adv & ADVERTISE_10HALF)
> +		result |= ADVERTISED_10baseT_Half;
> +	if (adv & ADVERTISE_10FULL)
> +		result |= ADVERTISED_10baseT_Full;
> +	if (adv & ADVERTISE_100HALF)
> +		result |= ADVERTISED_100baseT_Half;
> +	if (adv & ADVERTISE_100FULL)
> +		result |= ADVERTISED_100baseT_Full;
> +	if (adv & ADVERTISE_PAUSE_CAP)
> +		result |= ADVERTISED_Pause;
> +	if (adv & ADVERTISE_PAUSE_ASYM)
> +		result |= ADVERTISED_Asym_Pause;
> +
> +	return result;
> +}
> +
> +static inline uint32_t genphy_ctrl1000_to_ethtool_adv_t(uint32_t adv)
> +{
> +	uint32_t result = 0;
> +
> +	if (adv & ADVERTISE_1000HALF)
> +		result |= ADVERTISED_1000baseT_Half;
> +	if (adv & ADVERTISE_1000FULL)
> +		result |= ADVERTISED_1000baseT_Full;
> +
> +	return result;
> +}
> +
> +static inline uint32_t genphy_lpa_to_ethtool_lpa_t(uint32_t lpa)
> +{
> +	uint32_t result = 0;
> +
> +	if (lpa & LPA_LPACK)
> +		result |= ADVERTISED_Autoneg;
> +
> +	return result | genphy_adv_to_ethtool_adv_t(lpa);
> +}
> +
> +static inline uint32_t genphy_stat1000_to_ethtool_lpa_t(uint32_t lpa)
> +{
> +	uint32_t result = 0;
> +
> +	if (lpa & LPA_1000HALF)
> +		result |= ADVERTISED_1000baseT_Half;
> +	if (lpa & LPA_1000FULL)
> +		result |= ADVERTISED_1000baseT_Full;
> +
> +	return result;
> +}
> +
> +/* for usxgmii interface */
> +int macb_usxgmii_pcs_resume(struct phy_device *phydev);
> +void macb_usxgmii_pcs_suspend(struct phy_device *phydev);
> +int macb_usxgmii_pcs_check_for_link(struct phy_device *phydev);
> +int macb_gbe_pcs_check_for_link(struct phy_device *phydev);
> +
> +#endif /* _GENERIC_PHY_H */
> diff --git a/drivers/net/macb/base/macb_common.c b/drivers/net/macb/base/macb_common.c
> new file mode 100644
> index 0000000..c603758
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_common.c
> @@ -0,0 +1,650 @@
> +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#include <linux/mii.h>
> +#include <ctype.h>
> +#include "macb_uio.h"
> +
> +#define MACB_MDIO_TIMEOUT 1000000 /* in usecs */
> +
> +bool macb_is_gem(struct macb *bp)
> +{
> +	return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
> +}
> +
> +static bool hw_is_gem(struct macb *bp, bool native_io)
> +{
> +	u32 id;
> +	id = macb_readl(bp, MID);
> +	return MACB_BFEXT(IDNUM, id) >= 0x2;
> +}
> +
> +bool macb_hw_is_native_io(struct macb *bp)
> +{
> +	u32 value = MACB_BIT(LLB);
> +
> +	macb_writel(bp, NCR, value);
> +	value = macb_readl(bp, NCR);
> +	macb_writel(bp, NCR, 0);
> +
> +	return value == MACB_BIT(LLB);
> +}
> +
> +u32 macb_dbw(struct macb *bp)
> +{
> +	switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) {
> +	case 4:
> +		bp->data_bus_width = 128;
> +		return GEM_BF(DBW, GEM_DBW128);
> +	case 2:
> +		bp->data_bus_width = 64;
> +		return GEM_BF(DBW, GEM_DBW64);
> +	case 1:
> +	default:
> +		bp->data_bus_width = 32;
> +		return GEM_BF(DBW, GEM_DBW32);
> +	}
> +}
> +
> +void macb_probe_queues(uintptr_t base, bool native_io, unsigned int *queue_mask,
> +					   unsigned int *num_queues)
> +{
> +	unsigned int hw_q;
> +
> +	*queue_mask = 0x1;
> +	*num_queues = 1;
> +
> +	/* bit 0 is never set but queue 0 always exists */
> +	*queue_mask =
> +		(rte_le_to_cpu_32(rte_read32((void *)(base + GEM_DCFG6)))) & 0xff;
> +
> +	*queue_mask |= 0x1;
> +
> +	for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q)
> +		if (*queue_mask & (1 << hw_q))
> +			(*num_queues)++;
> +}
> +
> +void macb_configure_caps(struct macb *bp, const struct macb_config *dt_conf)
> +{
> +	u32 dcfg;
> +
> +	if (dt_conf)
> +		bp->caps = dt_conf->caps;
> +
> +	if (hw_is_gem(bp, bp->native_io)) {
> +		bp->caps |= MACB_CAPS_MACB_IS_GEM;
> +
> +		dcfg = gem_readl(bp, DCFG1);
> +		if (GEM_BFEXT(IRQCOR, dcfg) == 0)
> +			bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
> +
> +		dcfg = gem_readl(bp, DCFG2);
> +		if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
> +			bp->caps |= MACB_CAPS_FIFO_MODE;
> +	}
> +}
> +
> +int macb_iomem_init(const char *name, struct macb *bp, phys_addr_t paddr)
> +{
> +	int ret;
> +
> +	if (macb_uio_exist(name)) {
> +		ret = macb_uio_init(name, &bp->iomem);
> +		if (ret) {
> +			MACB_LOG(ERR, "failed to init uio device.");
> +			return -EFAULT;
> +		}
> +	} else {
> +		MACB_LOG(ERR, "uio device %s not exist.", name);
> +		return -EFAULT;
> +	}
> +
> +	ret = macb_uio_map(bp->iomem, &bp->paddr, (void **)(&bp->base), paddr);
> +	if (ret) {
> +		MACB_LOG(ERR, "Failed to remap macb uio device.");
> +		macb_uio_deinit(bp->iomem);
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +int macb_iomem_deinit(struct macb *bp)
> +{
> +	macb_uio_unmap(bp->iomem);
> +	macb_uio_deinit(bp->iomem);
> +	return 0;
> +}
> +
> +void macb_get_stats(struct macb *bp)
> +{
> +	struct macb_queue *queue;
> +	unsigned int i, q, idx;
> +	unsigned long *stat;
> +
> +	u64 *p = &bp->hw_stats.gem.tx_octets_31_0;
> +
> +	for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
> +		u32 offset = gem_statistics[i].offset;
> +		u64 val = macb_reg_readl(bp, offset);
> +
> +		*p += val;
> +
> +		if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
> +			/* Add GEM_OCTTXH, GEM_OCTRXH */
> +			val = macb_reg_readl(bp, offset + 4);
> +			*(++p) += val;
> +		}
> +	}
> +}
> +
> +static int macb_mdio_wait_for_idle(struct macb *bp)
> +{
> +	uint32_t val;
> +	uint64_t timeout = 0;
> +	for (;;) {
> +		val = macb_readl(bp, NSR);
> +		if (val & MACB_BIT(IDLE))
> +			break;
> +		if (timeout >= MACB_MDIO_TIMEOUT)
> +			break;
> +		timeout++;
> +		usleep(1);
> +	}
> +	return (val & MACB_BIT(IDLE)) ? 0 : -ETIMEDOUT;
> +}
> +
> +int macb_mdio_read(struct macb *bp, uint16_t phy_id, uint32_t regnum)
> +{
> +	int32_t status;
> +
> +	status = macb_mdio_wait_for_idle(bp);
> +	if (status < 0)
> +		return status;
> +
> +	if (regnum & MII_ADDR_C45) {
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C45_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C45_ADDR) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, (regnum >> 16) & 0x1F) |
> +					 MACB_BF(DATA, regnum & 0xFFFF) |
> +					 MACB_BF(CODE, MACB_MAN_C45_CODE)));
> +
> +		status = macb_mdio_wait_for_idle(bp);
> +		if (status < 0)
> +			return status;
> +
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C45_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C45_READ) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, (regnum >> 16) & 0x1F) |
> +					 MACB_BF(CODE, MACB_MAN_C45_CODE)));
> +	} else {
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C22_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C22_READ) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, regnum) | MACB_BF(CODE, MACB_MAN_C22_CODE)));
> +	}
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> +		;
> +
> +	status = MACB_BFEXT(DATA, macb_readl(bp, MAN));
> +
> +	return status;
> +}
> +
> +int macb_mdio_write(struct macb *bp, uint16_t phy_id, uint32_t regnum,
> +					uint16_t value)
> +{
> +	int32_t status;
> +	status = macb_mdio_wait_for_idle(bp);
> +	if (status < 0)
> +		return status;
> +
> +	if (regnum & MII_ADDR_C45) {
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C45_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C45_ADDR) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, (regnum >> 16) & 0x1F) |
> +					 MACB_BF(DATA, regnum & 0xFFFF) |
> +					 MACB_BF(CODE, MACB_MAN_C45_CODE)));
> +
> +		status = macb_mdio_wait_for_idle(bp);
> +		if (status < 0)
> +			return status;
> +
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C45_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C45_WRITE) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, (regnum >> 16) & 0x1F) |
> +					 MACB_BF(CODE, MACB_MAN_C45_CODE) | MACB_BF(DATA, value)));
> +
> +	} else {
> +		macb_writel(bp, MAN,
> +					(MACB_BF(SOF, MACB_MAN_C22_SOF) |
> +					 MACB_BF(RW, MACB_MAN_C22_WRITE) | MACB_BF(PHYA, phy_id) |
> +					 MACB_BF(REGA, regnum) | MACB_BF(CODE, MACB_MAN_C22_CODE) |
> +					 MACB_BF(DATA, value)));
> +	}
> +
> +	/* wait for end of transfer */
> +	while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
> +		;
> +
> +	return 0;
> +}
> +
> +void macb_gem1p0_sel_clk(struct macb *bp)
> +{
> +	int speed = 0;
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII) {
> +		if (bp->speed == SPEED_2500) {
> +			gem_writel(bp, DIV_SEL0_LN, 0x1);		/*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x2);		/*0x1c0c*/
> +			gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);	/*0x1c10*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x1);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x1);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x1);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x1);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x0);		/*0x1c34*/
> +			gem_writel(bp, TX_CLK_SEL3_0, 0x0);		/*0x1c70*/
> +			gem_writel(bp, TX_CLK_SEL4_0, 0x0);		/*0x1c74*/
> +			gem_writel(bp, RX_CLK_SEL3_0, 0x0);		/*0x1c78*/
> +			gem_writel(bp, RX_CLK_SEL4_0, 0x0);		/*0x1c7c*/
> +			speed = GEM_SPEED_2500;
> +		} else if (bp->speed == SPEED_1000) {
> +			gem_writel(bp, DIV_SEL0_LN, 0x4);		/*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x8);		/*0x1c0c*/
> +			gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);	/*0x1c10*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x0);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x0);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x1);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x1);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x0);		/*0x1c34*/
> +			gem_writel(bp, TX_CLK_SEL3_0, 0x0);		/*0x1c70*/
> +			gem_writel(bp, TX_CLK_SEL4_0, 0x0);		/*0x1c74*/
> +			gem_writel(bp, RX_CLK_SEL3_0, 0x0);		/*0x1c78*/
> +			gem_writel(bp, RX_CLK_SEL4_0, 0x0);		/*0x1c7c*/
> +			speed = GEM_SPEED_1000;
> +		} else if (bp->speed == SPEED_100 || bp->speed == SPEED_10) {
> +			gem_writel(bp, DIV_SEL0_LN, 0x4);		/*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x8);		/*0x1c0c*/
> +			gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);	/*0x1c10*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x0);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x1);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x1);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x1);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x0);		/*0x1c34*/
> +			gem_writel(bp, TX_CLK_SEL3_0, 0x1);		/*0x1c70*/
> +			gem_writel(bp, TX_CLK_SEL4_0, 0x0);		/*0x1c74*/
> +			gem_writel(bp, RX_CLK_SEL3_0, 0x0);		/*0x1c78*/
> +			gem_writel(bp, RX_CLK_SEL4_0, 0x1);		/*0x1c7c*/
> +			speed = GEM_SPEED_100;
> +		}
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_RGMII) {
> +		if (bp->speed == SPEED_1000) {
> +			gem_writel(bp, MII_SELECT, 0x1);		/*0x1c18*/
> +			gem_writel(bp, SEL_MII_ON_RGMII, 0x0);		/*0x1c1c*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x1);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x0);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x0);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x0);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x1);		/*0x1c34*/
> +			gem_writel(bp, CLK_250M_DIV10_DIV100_SEL, 0x0); /*0x1c38*/
> +			gem_writel(bp, RX_CLK_SEL5, 0x1);		/*0x1c48*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL0, 0x1);		/*0x1c80*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL1, 0x0);		/*0x1c84*/
> +			speed = GEM_SPEED_1000;
> +		} else if (bp->speed == SPEED_100) {
> +			gem_writel(bp, MII_SELECT, 0x1);		/*0x1c18*/
> +			gem_writel(bp, SEL_MII_ON_RGMII, 0x0);		/*0x1c1c*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x1);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x0);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x0);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x0);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x1);		/*0x1c34*/
> +			gem_writel(bp, CLK_250M_DIV10_DIV100_SEL, 0x0); /*0x1c38*/
> +			gem_writel(bp, RX_CLK_SEL5, 0x1);		/*0x1c48*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL0, 0x0);		/*0x1c80*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL1, 0x0);		/*0x1c84*/
> +			speed = GEM_SPEED_100;
> +		} else {
> +			gem_writel(bp, MII_SELECT, 0x1);		/*0x1c18*/
> +			gem_writel(bp, SEL_MII_ON_RGMII, 0x0);		/*0x1c1c*/
> +			gem_writel(bp, TX_CLK_SEL0, 0x0);		/*0x1c20*/
> +			gem_writel(bp, TX_CLK_SEL1, 0x1);		/*0x1c24*/
> +			gem_writel(bp, TX_CLK_SEL2, 0x0);		/*0x1c28*/
> +			gem_writel(bp, TX_CLK_SEL3, 0x0);		/*0x1c2c*/
> +			gem_writel(bp, RX_CLK_SEL0, 0x0);		/*0x1c30*/
> +			gem_writel(bp, RX_CLK_SEL1, 0x1);		/*0x1c34*/
> +			gem_writel(bp, CLK_250M_DIV10_DIV100_SEL, 0x1);	/*0x1c38*/
> +			gem_writel(bp, RX_CLK_SEL5, 0x1);		/*0x1c48*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL0, 0x0);		/*0x1c80*/
> +			gem_writel(bp, RGMII_TX_CLK_SEL1, 0x0);		/*0x1c84*/
> +			speed = GEM_SPEED_100;
> +		}
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_RMII) {
> +		speed = GEM_SPEED_100;
> +		gem_writel(bp, RX_CLK_SEL5, 0x1);			/*0x1c48*/
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX) {
> +		gem_writel(bp, DIV_SEL0_LN, 0x4);			/*0x1c08*/
> +		gem_writel(bp, DIV_SEL1_LN, 0x8);			/*0x1c0c*/
> +		gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);		/*0x1c10*/
> +		gem_writel(bp, TX_CLK_SEL0, 0x0);			/*0x1c20*/
> +		gem_writel(bp, TX_CLK_SEL1, 0x0);			/*0x1c24*/
> +		gem_writel(bp, TX_CLK_SEL2, 0x1);			/*0x1c28*/
> +		gem_writel(bp, TX_CLK_SEL3, 0x1);			/*0x1c2c*/
> +		gem_writel(bp, RX_CLK_SEL0, 0x1);			/*0x1c30*/
> +		gem_writel(bp, RX_CLK_SEL1, 0x0);			/*0x1c34*/
> +		gem_writel(bp, TX_CLK_SEL3_0, 0x1);			/*0x1c70*/
> +		gem_writel(bp, TX_CLK_SEL4_0, 0x0);			/*0x1c74*/
> +		gem_writel(bp, RX_CLK_SEL3_0, 0x0);			/*0x1c78*/
> +		gem_writel(bp, RX_CLK_SEL4_0, 0x1);			/*0x1c7c*/
> +		speed = GEM_SPEED_100;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX) {
> +		gem_writel(bp, DIV_SEL0_LN, 0x4);			/*0x1c08*/
> +		gem_writel(bp, DIV_SEL1_LN, 0x8);			/*0x1c0c*/
> +		gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);		/*0x1c10*/
> +		gem_writel(bp, TX_CLK_SEL0, 0x0);			/*0x1c20*/
> +		gem_writel(bp, TX_CLK_SEL1, 0x0);			/*0x1c24*/
> +		gem_writel(bp, TX_CLK_SEL2, 0x0);			/*0x1c28*/
> +		gem_writel(bp, TX_CLK_SEL3, 0x1);			/*0x1c2c*/
> +		gem_writel(bp, RX_CLK_SEL0, 0x1);			/*0x1c30*/
> +		gem_writel(bp, RX_CLK_SEL1, 0x0);			/*0x1c34*/
> +		gem_writel(bp, TX_CLK_SEL3_0, 0x0);			/*0x1c70*/
> +		gem_writel(bp, TX_CLK_SEL4_0, 0x0);			/*0x1c74*/
> +		gem_writel(bp, RX_CLK_SEL3_0, 0x0);			/*0x1c78*/
> +		gem_writel(bp, RX_CLK_SEL4_0, 0x0);			/*0x1c7c*/
> +		speed = GEM_SPEED_1000;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX) {
> +		gem_writel(bp, DIV_SEL0_LN, 0x1);			/*0x1c08*/
> +		gem_writel(bp, DIV_SEL1_LN, 0x2);			/*0x1c0c*/
> +		gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);		/*0x1c10*/
> +		gem_writel(bp, TX_CLK_SEL0, 0x0);			/*0x1c20*/
> +		gem_writel(bp, TX_CLK_SEL1, 0x1);			/*0x1c24*/
> +		gem_writel(bp, TX_CLK_SEL2, 0x1);			/*0x1c28*/
> +		gem_writel(bp, TX_CLK_SEL3, 0x1);			/*0x1c2c*/
> +		gem_writel(bp, RX_CLK_SEL0, 0x1);			/*0x1c30*/
> +		gem_writel(bp, RX_CLK_SEL1, 0x0);			/*0x1c34*/
> +		gem_writel(bp, TX_CLK_SEL3_0, 0x0);			/*0x1c70*/
> +		gem_writel(bp, TX_CLK_SEL4_0, 0x0);			/*0x1c74*/
> +		gem_writel(bp, RX_CLK_SEL3_0, 0x0);			/*0x1c78*/
> +		gem_writel(bp, RX_CLK_SEL4_0, 0x0);			/*0x1c7c*/
> +		speed = GEM_SPEED_2500;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII) {
> +		gem_writel(bp, SRC_SEL_LN, 0x1);			/*0x1c04*/
> +		if (bp->speed == SPEED_5000) {
> +			gem_writel(bp, DIV_SEL0_LN, 0x8);		/*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x2);		/*0x1cc*/
> +			speed = GEM_SPEED_5000;
> +		} else {
> +			gem_writel(bp, DIV_SEL0_LN, 0x4);		/*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x1);		/*0x1c0c*/
> +			gem_writel(bp, TX_CLK_SEL3_0, 0x0);		/*0x1c70*/
> +			gem_writel(bp, RX_CLK_SEL4_0, 0x0);		/*0x1c7c*/
> +			speed = GEM_SPEED_10000;
> +		}
> +		gem_writel(bp, PMA_XCVR_POWER_STATE, 0x1);		/*0x1c10*/
> +	}
> +
> +	/*HS_MAC_CONFIG(0x0050) provide rate to the external*/
> +	gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, speed, gem_readl(bp, HS_MAC_CONFIG)));
> +}
> +
> +void macb_gem2p0_sel_clk(struct macb *bp)
> +{
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII) {
> +		if (bp->speed == SPEED_100 || bp->speed == SPEED_10) {
> +			gem_writel(bp, DIV_SEL0_LN, 0x4); /*0x1c08*/
> +			gem_writel(bp, DIV_SEL1_LN, 0x8); /*0x1c0c*/
> +		}
> +	}
> +
> +	if (bp->speed == SPEED_100 || bp->speed == SPEED_10)
> +		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, GEM_SPEED_100,
> +							gem_readl(bp, HS_MAC_CONFIG)));
> +	else if (bp->speed == SPEED_1000)
> +		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, GEM_SPEED_1000,
> +							gem_readl(bp, HS_MAC_CONFIG)));
> +	else if (bp->speed == SPEED_2500)
> +		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, GEM_SPEED_2500,
> +							gem_readl(bp, HS_MAC_CONFIG)));
> +	else if (bp->speed == SPEED_5000)
> +		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, GEM_SPEED_5000,
> +							gem_readl(bp, HS_MAC_CONFIG)));
> +	else if (bp->speed == SPEED_10000)
> +		gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, GEM_SPEED_10000,
> +							gem_readl(bp, HS_MAC_CONFIG)));
> +}
> +
> +/* When PCSSEL is set to 1, PCS will be in a soft reset state,
> + * The auto negotiation configuration must be done after
> + * pcs soft reset is completed.
> + */
> +static int macb_mac_pcssel_config(struct macb *bp)
> +{
> +	u32 old_ctrl, ctrl;
> +
> +	ctrl = macb_or_gem_readl(bp, NCFGR);
> +	old_ctrl = ctrl;
> +
> +	ctrl |= GEM_BIT(PCSSEL);
> +
> +	if (old_ctrl ^ ctrl)
> +		macb_or_gem_writel(bp, NCFGR, ctrl);
> +
> +	rte_delay_ms(1);
> +	return 0;
> +}
> +
> +int macb_mac_with_pcs_config(struct macb *bp)
> +{
> +	u32 old_ctrl, ctrl;
> +	u32 old_ncr, ncr;
> +	u32 config;
> +	u32 pcsctrl;
> +
> +	macb_mac_pcssel_config(bp);
> +
> +	ncr = macb_readl(bp, NCR);
> +	old_ncr = ncr;
> +	ctrl = macb_or_gem_readl(bp, NCFGR);
> +	old_ctrl = ctrl;
> +
> +	ncr &= ~(GEM_BIT(ENABLE_HS_MAC) | MACB_BIT(2PT5G));
> +	ctrl &= ~(GEM_BIT(SGMIIEN) | MACB_BIT(SPD) | MACB_BIT(FD));
> +	if (macb_is_gem(bp))
> +		ctrl &= ~GEM_BIT(GBE);
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX) {
> +		ctrl |= GEM_BIT(GBE);
> +		ncr |= MACB_BIT(2PT5G);
> +		pcsctrl = gem_readl(bp, PCSCTRL);
> +		pcsctrl &= ~GEM_BIT(PCS_AUTO_NEG_ENB);
> +		gem_writel(bp, PCSCTRL, pcsctrl);
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII) {
> +		ncr |= GEM_BIT(ENABLE_HS_MAC);
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX) {
> +		ctrl |= GEM_BIT(GBE);
> +		pcsctrl = gem_readl(bp, PCSCTRL);
> +		pcsctrl |= GEM_BIT(PCS_AUTO_NEG_ENB);
> +		gem_writel(bp, PCSCTRL, pcsctrl);
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX) {
> +		ctrl |= MACB_BIT(SPD);
> +		pcsctrl = gem_readl(bp, PCSCTRL);
> +		pcsctrl |= GEM_BIT(PCS_AUTO_NEG_ENB);
> +		gem_writel(bp, PCSCTRL, pcsctrl);
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link) {
> +		ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(GBE);
> +		pcsctrl = gem_readl(bp, PCSCTRL);
> +		pcsctrl |= GEM_BIT(PCS_AUTO_NEG_ENB);
> +		gem_writel(bp, PCSCTRL, pcsctrl);
> +	}
> +
> +	if (bp->duplex)
> +		ctrl |= MACB_BIT(FD);
> +
> +	/* Apply the new configuration, if any */
> +	if (old_ctrl ^ ctrl)
> +		macb_or_gem_writel(bp, NCFGR, ctrl);
> +
> +	if (old_ncr ^ ncr)
> +		macb_or_gem_writel(bp, NCR, ncr);
> +
> +	/*config usx control*/
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII) {
> +		config = gem_readl(bp, USX_CONTROL);
> +		if (bp->speed == SPEED_10000) {
> +			config = GEM_BFINS(SERDES_RATE, MACB_SERDES_RATE_10G, config);
> +			config = GEM_BFINS(USX_CTRL_SPEED, GEM_SPEED_10000, config);
> +		} else if (bp->speed == SPEED_5000) {
> +			config = GEM_BFINS(SERDES_RATE, MACB_SERDES_RATE_5G, config);
> +			config = GEM_BFINS(USX_CTRL_SPEED, GEM_SPEED_5000, config);
> +		}
> +
> +		config &= ~(GEM_BIT(TX_SCR_BYPASS) | GEM_BIT(RX_SCR_BYPASS));
> +		/* enable rx and tx */
> +		config &= ~(GEM_BIT(RX_SYNC_RESET));
> +		config |= GEM_BIT(SIGNAL_OK) | GEM_BIT(TX_EN);
> +		gem_writel(bp, USX_CONTROL, config);
> +	}
> +
> +	return 0;
> +}
> +
> +int macb_link_change(struct macb *bp)
> +{
> +	struct phy_device *phydev = bp->phydev;
> +	uint32_t config, ncr, pcsctrl;
> +	bool sync_link_info = true;
> +
> +	if (!bp->link)
> +		return 0;
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
> +		bp->fixed_link)
> +		sync_link_info = false;
> +
> +	if (sync_link_info) {
> +		/* sync phy link info to mac */
> +		if (bp->phydrv_used) {
> +			bp->duplex = phydev->duplex;
> +			bp->speed = phydev->speed;
> +		}
> +
> +		config = macb_readl(bp, NCFGR);
> +		config &= ~(MACB_BIT(FD) | MACB_BIT(SPD) | GEM_BIT(GBE));
> +
> +		if (bp->duplex)
> +			config |= MACB_BIT(FD);
> +
> +		if (bp->speed == SPEED_100)
> +			config |= MACB_BIT(SPD);
> +		else if (bp->speed == SPEED_1000 || bp->speed == SPEED_2500)
> +			config |= GEM_BIT(GBE);
> +
> +		macb_writel(bp, NCFGR, config);
> +
> +		if (bp->speed == SPEED_2500) {
> +			ncr = macb_readl(bp, NCR);
> +			ncr |= MACB_BIT(2PT5G);
> +			macb_writel(bp, NCR, ncr);
> +			pcsctrl = gem_readl(bp, PCSCTRL);
> +			pcsctrl &= ~GEM_BIT(PCS_AUTO_NEG_ENB);
> +			gem_writel(bp, PCSCTRL, pcsctrl);
> +		}
> +	}
> +
> +	if ((bp->caps & MACB_CAPS_SEL_CLK_HW) && bp->sel_clk_hw)
> +		bp->sel_clk_hw(bp);
> +
> +	return 0;
> +}
> +
> +void macb_check_for_link(struct macb *bp)
> +{
> +	int link_flag;
> +	struct phy_device *phydev = bp->phydev;
> +
> +	if (phydev->drv && phydev->drv->check_for_link) {
> +		link_flag = phydev->drv->check_for_link(phydev);
> +		if (link_flag > 0)
> +			bp->link = (uint16_t)link_flag;
> +		else
> +			bp->link = 0;
> +	}
> +}
> +
> +void macb_setup_link(struct macb *bp)
> +{
> +	struct phy_device *phydev = bp->phydev;
> +
> +	/* phy setup link */
> +	if (phydev->drv && phydev->drv->force_speed_duplex)
> +		phydev->drv->force_speed_duplex(phydev);
> +}
> +
> +void macb_reset_hw(struct macb *bp)
> +{
> +	u32 i;
> +	u32 ISR;
> +	u32 IDR;
> +	u32 TBQP;
> +	u32 TBQPH;
> +	u32 RBQP;
> +	u32 RBQPH;
> +
> +	u32 ctrl = macb_readl(bp, NCR);
> +
> +	/* Disable RX and TX (XXX: Should we halt the transmission
> +	 * more gracefully?)
> +	 */
> +	ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
> +
> +	/* Clear the stats registers (XXX: Update stats first?) */
> +	ctrl |= MACB_BIT(CLRSTAT);
> +
> +	macb_writel(bp, NCR, ctrl);
> +	rte_delay_ms(1);
> +
> +	/* Clear all status flags */
> +	macb_writel(bp, TSR, -1);
> +	macb_writel(bp, RSR, -1);
> +
> +	/* queue0 uses legacy registers */
> +	macb_queue_flush(bp, MACB_TBQP, 1);
> +	macb_queue_flush(bp, MACB_TBQPH, 0);
> +	macb_queue_flush(bp, MACB_RBQP, 1);
> +	macb_queue_flush(bp, MACB_RBQPH, 0);
> +
> +	/* clear all queue register */
> +	for (i = 1; i < bp->num_queues; i++) {
> +		ISR = GEM_ISR(i - 1);
> +		IDR = GEM_IDR(i - 1);
> +		TBQP = GEM_TBQP(i - 1);
> +		TBQPH = GEM_TBQPH(i - 1);
> +		RBQP = GEM_RBQP(i - 1);
> +		RBQPH = GEM_RBQPH(i - 1);
> +
> +		macb_queue_flush(bp, IDR, -1);
> +		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> +			macb_queue_flush(bp, ISR, -1);
> +		macb_queue_flush(bp, TBQP, 1);
> +		macb_queue_flush(bp, TBQPH, 0);
> +		macb_queue_flush(bp, RBQP, 1);
> +		macb_queue_flush(bp, RBQPH, 0);
> +	}
> +}
> diff --git a/drivers/net/macb/base/macb_common.h b/drivers/net/macb/base/macb_common.h
> new file mode 100644
> index 0000000..268d037
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_common.h
> @@ -0,0 +1,251 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_COMMON_H_
> +#define _MACB_COMMON_H_
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <fcntl.h>
> +
> +#include <linux/ethtool.h>
> +#include <linux/sockios.h>
> +#include <net/if.h>
> +#include <net/if_arp.h>
> +#include <sys/socket.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/ioctl.h>
> +
> +#include <rte_common.h>
> +#include <rte_memcpy.h>
> +#include <rte_malloc.h>
> +#include <rte_memzone.h>
> +#include <rte_byteorder.h>
> +#include <rte_cycles.h>
> +#include <rte_spinlock.h>
> +#include <rte_log.h>
> +#include <rte_random.h>
> +#include <rte_io.h>
> +
> +#include "macb_type.h"
> +#include "macb_hw.h"
> +#include "generic_phy.h"
> +#include "macb_errno.h"
> +#include "../macb_log.h"
> +#include "macb_uio.h"
> +
> +#define BIT(nr)	(1UL << (nr))
> +
> +#define MACB_MAX_PORT_NUM 4
> +#define	MACB_MIN_RING_DESC	64
> +#define	MACB_MAX_RING_DESC	4096
> +#define MACB_RXD_ALIGN	64
> +#define MACB_TXD_ALIGN	64
> +
> +#define TX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)	\
> +				 * (bp)->tx_ring_size)
> +#define RX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)	\
> +				 * (bp)->rx_ring_size)
> +#define MACB_TX_LEN_ALIGN	8
> +#define MACB_RX_LEN_ALIGN	8
> +
> +
> +#define MACB_RX_RING_SIZE	256
> +#define MACB_TX_RING_SIZE	256
> +#define MAX_JUMBO_FRAME_SIZE	10240
> +#define MIN_JUMBO_FRAME_SIZE	16
> +
> +#define RX_BUFFER_MULTIPLE	64  /* bytes */
> +#define PCLK_HZ_2 20000000
> +#define PCLK_HZ_4 40000000
> +#define PCLK_HZ_8 80000000
> +#define PCLK_HZ_12 120000000
> +#define PCLK_HZ_16 160000000
> +
> +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
> +#define lower_32_bits(n) ((u32)(n))
> +#define cpu_to_le16(x)  (x)
> +#define cpu_to_le32(x)  (x)
> +
> +#define MACB_MII_CLK_ENABLE 0x1
> +#define MACB_MII_CLK_DISABLE 0x0
> +
> +/* dtb for Phytium MAC */
> +#define OF_PHYTIUM_GEM1P0_MAC	"cdns,phytium-gem-1.0"	/* Phytium 1.0 MAC */
> +#define OF_PHYTIUM_GEM2P0_MAC	"cdns,phytium-gem-2.0"	/* Phytium 2.0 MAC */
> +
> +/* acpi for Phytium MAC */
> +#define ACPI_PHYTIUM_GEM1P0_MAC	"PHYT0036"	/* Phytium 1.0  MAC */
> +
> +typedef u64 netdev_features_t;
> +
> +/**
> + * Interface Mode definitions.
> + * Warning: must be consistent with dpdk definition !
> + */
> +typedef enum {
> +	MACB_PHY_INTERFACE_MODE_NA,
> +	MACB_PHY_INTERFACE_MODE_INTERNAL,
> +	MACB_PHY_INTERFACE_MODE_MII,
> +	MACB_PHY_INTERFACE_MODE_GMII,
> +	MACB_PHY_INTERFACE_MODE_SGMII,
> +	MACB_PHY_INTERFACE_MODE_TBI,
> +	MACB_PHY_INTERFACE_MODE_REVMII,
> +	MACB_PHY_INTERFACE_MODE_RMII,
> +	MACB_PHY_INTERFACE_MODE_RGMII,
> +	MACB_PHY_INTERFACE_MODE_RGMII_ID,
> +	MACB_PHY_INTERFACE_MODE_RGMII_RXID,
> +	MACB_PHY_INTERFACE_MODE_RGMII_TXID,
> +	MACB_PHY_INTERFACE_MODE_RTBI,
> +	MACB_PHY_INTERFACE_MODE_SMII,
> +	MACB_PHY_INTERFACE_MODE_XGMII,
> +	MACB_PHY_INTERFACE_MODE_MOCA,
> +	MACB_PHY_INTERFACE_MODE_QSGMII,
> +	MACB_PHY_INTERFACE_MODE_TRGMII,
> +	MACB_PHY_INTERFACE_MODE_100BASEX,
> +	MACB_PHY_INTERFACE_MODE_1000BASEX,
> +	MACB_PHY_INTERFACE_MODE_2500BASEX,
> +	MACB_PHY_INTERFACE_MODE_5GBASER,
> +	MACB_PHY_INTERFACE_MODE_RXAUI,
> +	MACB_PHY_INTERFACE_MODE_XAUI,
> +	/* 10GBASE-R, XFI, SFI - single lane 10G Serdes */
> +	MACB_PHY_INTERFACE_MODE_10GBASER,
> +	MACB_PHY_INTERFACE_MODE_USXGMII,
> +	/* 10GBASE-KR - with Clause 73 AN */
> +	MACB_PHY_INTERFACE_MODE_10GKR,
> +	MACB_PHY_INTERFACE_MODE_MAX,
> +} phy_interface_t;
> +
> +typedef enum {
> +	DEV_TYPE_PHYTIUM_GEM1P0_MAC,
> +	DEV_TYPE_PHYTIUM_GEM2P0_MAC,
> +	DEV_TYPE_DEFAULT,
> +} dev_type_t;
> +
> +struct macb_dma_desc {
> +	u32	addr;
> +	u32	ctrl;
> +};
> +
> +struct macb_dma_desc_64 {
> +	u32 addrh;
> +	u32 resvd;
> +};
> +
> +struct macb_dma_desc_ptp {
> +	u32	ts_1;
> +	u32	ts_2;
> +};
> +
> +struct macb;
> +struct macb_rx_queue;
> +struct macb_tx_queue;
> +
> +struct macb_config {
> +	u32			caps;
> +	unsigned int		dma_burst_length;
> +	int	jumbo_max_len;
> +	void (*sel_clk_hw)(struct macb *bp);
> +};
> +
> +struct macb {
> +	struct macb_iomem		*iomem;
> +	uintptr_t		base;
> +	phys_addr_t		paddr;
> +	bool			native_io;
> +	bool			rx_bulk_alloc_allowed;
> +	bool			rx_vec_allowed;
> +
> +	size_t			rx_buffer_size;
> +
> +	unsigned int		rx_ring_size;
> +	unsigned int		tx_ring_size;
> +
> +	unsigned int		num_queues;
> +	unsigned int		queue_mask;
> +
> +	struct rte_eth_dev	*dev;
> +	union {
> +		struct macb_stats	macb;
> +		struct gem_stats	gem;
> +	} hw_stats;
> +
> +	uint16_t phyad;
> +	uint32_t speed;
> +	uint16_t link;
> +	uint16_t duplex;
> +	uint16_t autoneg;
> +	uint16_t fixed_link;
> +	u32			caps;
> +	unsigned int		dma_burst_length;
> +
> +	unsigned int		rx_frm_len_mask;
> +	unsigned int		jumbo_max_len;
> +
> +	uint8_t hw_dma_cap;
> +
> +	bool phydrv_used;
> +	struct phy_device *phydev;
> +
> +	int	rx_bd_rd_prefetch;
> +	int	tx_bd_rd_prefetch;
> +
> +	u32 max_tuples;
> +	phy_interface_t		phy_interface;
> +	u32 dev_type;
> +	u32 data_bus_width;
> +	/* PHYTIUM  sel clk */
> +	void (*sel_clk_hw)(struct macb *bp);
> +};
> +
> +static inline u32 macb_reg_readl(struct macb *bp, int offset)
> +{
> +	return rte_le_to_cpu_32(rte_read32((void *)(bp->base + offset)));
> +}
> +
> +static inline void macb_reg_writel(struct macb *bp, int offset, u32 value)
> +{
> +	rte_write32(rte_cpu_to_le_32(value), (void *)(bp->base + offset));
> +}
> +
> +#define macb_readl(port, reg)		macb_reg_readl((port), MACB_##reg)
> +#define macb_writel(port, reg, value)	macb_reg_writel((port), MACB_##reg, (value))
> +#define gem_readl(port, reg)		macb_reg_readl((port), GEM_##reg)
> +#define gem_writel(port, reg, value)	macb_reg_writel((port), GEM_##reg, (value))
> +#define queue_readl(queue, reg)		macb_reg_readl((queue)->bp, (queue)->reg)
> +#define queue_writel(queue, reg, value)	macb_reg_writel((queue)->bp, (queue)->reg, (value))
> +#define macb_queue_flush(port, reg, value)	macb_reg_writel((port), (reg), (value))
> +#define gem_readl_n(port, reg, idx)		macb_reg_readl((port), GEM_##reg + idx * 4)
> +#define gem_writel_n(port, reg, idx, value) \
> +	macb_reg_writel((port), GEM_##reg + idx * 4, (value))
> +
> +bool macb_is_gem(struct macb *bp);
> +bool macb_hw_is_native_io(struct macb *bp);
> +u32 macb_dbw(struct macb *bp);
> +void macb_probe_queues(uintptr_t base, bool native_io,
> +		       unsigned int *queue_mask, unsigned int *num_queues);
> +void macb_configure_caps(struct macb *bp, const struct macb_config *dt_conf);
> +
> +int macb_iomem_init(const char *name, struct macb *bp, phys_addr_t paddr);
> +int macb_iomem_deinit(struct macb *bp);
> +
> +void macb_get_stats(struct macb *bp);
> +int macb_mdio_read(struct macb *bp, uint16_t phy_id, uint32_t regnum);
> +int macb_mdio_write(struct macb *bp, uint16_t phy_id, uint32_t regnum, uint16_t value);
> +
> +void macb_gem1p0_sel_clk(struct macb *bp);
> +void macb_gem2p0_sel_clk(struct macb *bp);
> +
> +int macb_mac_with_pcs_config(struct macb *bp);
> +
> +int macb_link_change(struct macb *bp);
> +void macb_check_for_link(struct macb *bp);
> +void macb_setup_link(struct macb *bp);
> +void macb_reset_hw(struct macb *bp);
> +
> +#endif /* _MACB_COMMON_H_ */
> diff --git a/drivers/net/macb/base/macb_errno.h b/drivers/net/macb/base/macb_errno.h
> new file mode 100644
> index 0000000..5c0bce6
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_errno.h
> @@ -0,0 +1,58 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_ERRNO_H_
> +#define _MACB_ERRNO_H_
> +
> +#include <errno.h>
> +
> +#ifndef EPERM
> +#define EPERM		1
> +#endif /* EPERM */
> +#ifndef ENOENT
> +#define ENOENT		2
> +#endif /* ENOENT */
> +#ifndef EIO
> +#define EIO		5
> +#endif /* EIO */
> +#ifndef ENXIO
> +#define ENXIO		6
> +#endif /* ENXIO */
> +#ifndef ENOMEM
> +#define ENOMEM		12
> +#endif /* ENOMEM */
> +#ifndef EACCES
> +#define EACCES		13
> +#endif /* EACCES */
> +#ifndef EFAULT
> +#define EFAULT		14
> +#endif /* EFAULT */
> +#ifndef EBUSY
> +#define EBUSY		16
> +#endif /* EBUSY */
> +#ifndef EEXIST
> +#define EEXIST		17
> +#endif /* EEXIST */
> +#ifndef ENODEV
> +#define ENODEV		19
> +#endif /* ENODEV */
> +#ifndef EINVAL
> +#define EINVAL		22
> +#endif /* EINVAL */
> +#ifndef ENOSPC
> +#define ENOSPC		28
> +#endif /* ENOSPC */
> +#ifndef ENOMSG
> +#define ENOMSG		42
> +#endif /* ENOMSG */
> +
> +#ifndef ENOBUFS
> +#define ENOBUFS		105
> +#endif /* ENOBUFS */
> +
> +#ifndef ENOTSUP
> +#define ENOTSUP		252
> +#endif /* ENOTSUP */
> +
> +#endif /* _MACB_ERRNO_H_ */
> diff --git a/drivers/net/macb/base/macb_hw.h b/drivers/net/macb/base/macb_hw.h
> new file mode 100644
> index 0000000..c831ecf
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_hw.h
> @@ -0,0 +1,1138 @@
> +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
> + * Atmel MACB Ethernet Controller driver
> + * Copyright (C) 2004-2006 Atmel Corporation
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _MACB_H
> +#define _MACB_H
> +
> +
> +#define MACB_EXT_DESC
> +
> +#define MACB_GREGS_NBR 16
> +#define MACB_GREGS_VERSION 2
> +#define MACB_MAX_QUEUES 8
> +#define MACB_MAX_JUMBO_FRAME 0x2800
> +
> +/* MACB register offsets */
> +#define MACB_NCR		0x0000 /* Network Control */
> +#define MACB_NCFGR		0x0004 /* Network Config */
> +#define MACB_NSR		0x0008 /* Network Status */
> +#define MACB_TAR		0x000c /* AT91RM9200 only */
> +#define MACB_TCR		0x0010 /* AT91RM9200 only */
> +#define MACB_TSR		0x0014 /* Transmit Status */
> +#define MACB_RBQP		0x0018 /* RX Q Base Address */
> +#define MACB_TBQP		0x001c /* TX Q Base Address */
> +#define MACB_RSR		0x0020 /* Receive Status */
> +#define MACB_ISR		0x0024 /* Interrupt Status */
> +#define MACB_IER		0x0028 /* Interrupt Enable */
> +#define MACB_IDR		0x002c /* Interrupt Disable */
> +#define MACB_IMR		0x0030 /* Interrupt Mask */
> +#define MACB_MAN		0x0034 /* PHY Maintenance */
> +#define MACB_PTR		0x0038
> +#define MACB_PFR		0x003c
> +#define MACB_FTO		0x0040
> +#define MACB_SCF		0x0044
> +#define MACB_MCF		0x0048
> +#define MACB_FRO		0x004c
> +#define MACB_FCSE		0x0050
> +#define MACB_ALE		0x0054
> +#define MACB_DTF		0x0058
> +#define MACB_LCOL		0x005c
> +#define MACB_EXCOL		0x0060
> +#define MACB_TUND		0x0064
> +#define MACB_CSE		0x0068
> +#define MACB_RRE		0x006c
> +#define MACB_ROVR		0x0070
> +#define MACB_RSE		0x0074
> +#define MACB_ELE		0x0078
> +#define MACB_RJA		0x007c
> +#define MACB_USF		0x0080
> +#define MACB_STE		0x0084
> +#define MACB_RLE		0x0088
> +#define MACB_TPF		0x008c
> +#define MACB_HRB		0x0090
> +#define MACB_HRT		0x0094
> +#define MACB_SA1B		0x0098
> +#define MACB_SA1T		0x009c
> +#define MACB_SA2B		0x00a0
> +#define MACB_SA2T		0x00a4
> +#define MACB_SA3B		0x00a8
> +#define MACB_SA3T		0x00ac
> +#define MACB_SA4B		0x00b0
> +#define MACB_SA4T		0x00b4
> +#define MACB_TID		0x00b8
> +#define MACB_TPQ		0x00bc
> +#define MACB_USRIO		0x00c0
> +#define MACB_WOL		0x00c4
> +#define MACB_MID		0x00fc
> +#define MACB_TBQPH		0x04C8
> +#define MACB_RBQPH		0x04D4
> +
> +/* GEM register offsets. */
> +#define GEM_NCR			0x0000 /* Network Config */
> +#define GEM_NCFGR		0x0004 /* Network Config */
> +#define GEM_USRIO		0x000c /* User IO */
> +#define GEM_DMACFG		0x0010 /* DMA Configuration */
> +#define GEM_JML			0x0048 /* Jumbo Max Length */
> +#define GEM_HS_MAC_CONFIG       0x0050 /* Hs mac config register*/
> +#define GEM_AXI_PIPE    0x0054 /* Axi max pipeline register*/
> +#define GEM_HRB			0x0080 /* Hash Bottom */
> +#define GEM_HRT			0x0084 /* Hash Top */
> +#define GEM_SA1B		0x0088 /* Specific1 Bottom */
> +#define GEM_SA1T		0x008C /* Specific1 Top */
> +#define GEM_SA2B		0x0090 /* Specific2 Bottom */
> +#define GEM_SA2T		0x0094 /* Specific2 Top */
> +#define GEM_SA3B		0x0098 /* Specific3 Bottom */
> +#define GEM_SA3T		0x009C /* Specific3 Top */
> +#define GEM_SA4B		0x00A0 /* Specific4 Bottom */
> +#define GEM_SA4T		0x00A4 /* Specific4 Top */
> +#define GEM_EFTSH		0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */
> +#define GEM_EFRSH		0x00ec /* PTP Event Frame Received Seconds Register 47:32 */
> +#define GEM_PEFTSH		0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */
> +#define GEM_PEFRSH		0x00f4 /* PTP Peer Event Frame Received Seconds Register 47:32 */
> +#define GEM_OTX			0x0100 /* Octets transmitted */
> +#define GEM_OCTTXL		0x0100 /* Octets transmitted [31:0] */
> +#define GEM_OCTTXH		0x0104 /* Octets transmitted [47:32] */
> +#define GEM_TXCNT		0x0108 /* Frames Transmitted counter */
> +#define GEM_TXBCCNT		0x010c /* Broadcast Frames counter */
> +#define GEM_TXMCCNT		0x0110 /* Multicast Frames counter */
> +#define GEM_TXPAUSECNT		0x0114 /* Pause Frames Transmitted Counter */
> +#define GEM_TX64CNT		0x0118 /* 64 byte Frames TX counter */
> +#define GEM_TX65CNT		0x011c /* 65-127 byte Frames TX counter */
> +#define GEM_TX128CNT		0x0120 /* 128-255 byte Frames TX counter */
> +#define GEM_TX256CNT		0x0124 /* 256-511 byte Frames TX counter */
> +#define GEM_TX512CNT		0x0128 /* 512-1023 byte Frames TX counter */
> +#define GEM_TX1024CNT		0x012c /* 1024-1518 byte Frames TX counter */
> +#define GEM_TX1519CNT		0x0130 /* 1519+ byte Frames TX counter */
> +#define GEM_TXURUNCNT		0x0134 /* TX under run error counter */
> +#define GEM_SNGLCOLLCNT		0x0138 /* Single Collision Frame Counter */
> +#define GEM_MULTICOLLCNT	0x013c /* Multiple Collision Frame Counter */
> +#define GEM_EXCESSCOLLCNT	0x0140 /* Excessive Collision Frame Counter */
> +#define GEM_LATECOLLCNT		0x0144 /* Late Collision Frame Counter */
> +#define GEM_TXDEFERCNT		0x0148 /* Deferred Transmission Frame Counter */
> +#define GEM_TXCSENSECNT		0x014c /* Carrier Sense Error Counter */
> +#define GEM_ORX			0x0150 /* Octets received */
> +#define GEM_OCTRXL		0x0150 /* Octets received [31:0] */
> +#define GEM_OCTRXH		0x0154 /* Octets received [47:32] */
> +#define GEM_RXCNT		0x0158 /* Frames Received Counter */
> +#define GEM_RXBROADCNT		0x015c /* Broadcast Frames Received Counter */
> +#define GEM_RXMULTICNT		0x0160 /* Multicast Frames Received Counter */
> +#define GEM_RXPAUSECNT		0x0164 /* Pause Frames Received Counter */
> +#define GEM_RX64CNT		0x0168 /* 64 byte Frames RX Counter */
> +#define GEM_RX65CNT		0x016c /* 65-127 byte Frames RX Counter */
> +#define GEM_RX128CNT		0x0170 /* 128-255 byte Frames RX Counter */
> +#define GEM_RX256CNT		0x0174 /* 256-511 byte Frames RX Counter */
> +#define GEM_RX512CNT		0x0178 /* 512-1023 byte Frames RX Counter */
> +#define GEM_RX1024CNT		0x017c /* 1024-1518 byte Frames RX Counter */
> +#define GEM_RX1519CNT		0x0180 /* 1519+ byte Frames RX Counter */
> +#define GEM_RXUNDRCNT		0x0184 /* Undersize Frames Received Counter */
> +#define GEM_RXOVRCNT		0x0188 /* Oversize Frames Received Counter */
> +#define GEM_RXJABCNT		0x018c /* Jabbers Received Counter */
> +#define GEM_RXFCSCNT		0x0190 /* Frame Check Sequence Error Counter */
> +#define GEM_RXLENGTHCNT		0x0194 /* Length Field Error Counter */
> +#define GEM_RXSYMBCNT		0x0198 /* Symbol Error Counter */
> +#define GEM_RXALIGNCNT		0x019c /* Alignment Error Counter */
> +#define GEM_RXRESERRCNT		0x01a0 /* Receive Resource Error Counter */
> +#define GEM_RXORCNT		0x01a4 /* Receive Overrun Counter */
> +#define GEM_RXIPCCNT		0x01a8 /* IP header Checksum Error Counter */
> +#define GEM_RXTCPCCNT		0x01ac /* TCP Checksum Error Counter */
> +#define GEM_RXUDPCCNT		0x01b0 /* UDP Checksum Error Counter */
> +#define GEM_TISUBN		0x01bc /* 1588 Timer Increment Sub-ns */
> +#define GEM_TSH			0x01c0 /* 1588 Timer Seconds High */
> +#define GEM_TSL			0x01d0 /* 1588 Timer Seconds Low */
> +#define GEM_TN			0x01d4 /* 1588 Timer Nanoseconds */
> +#define GEM_TA			0x01d8 /* 1588 Timer Adjust */
> +#define GEM_TI			0x01dc /* 1588 Timer Increment */
> +#define GEM_EFTSL		0x01e0 /* PTP Event Frame Tx Seconds Low */
> +#define GEM_EFTN		0x01e4 /* PTP Event Frame Tx Nanoseconds */
> +#define GEM_EFRSL		0x01e8 /* PTP Event Frame Rx Seconds Low */
> +#define GEM_EFRN		0x01ec /* PTP Event Frame Rx Nanoseconds */
> +#define GEM_PEFTSL		0x01f0 /* PTP Peer Event Frame Tx Secs Low */
> +#define GEM_PEFTN		0x01f4 /* PTP Peer Event Frame Tx Ns */
> +#define GEM_PEFRSL		0x01f8 /* PTP Peer Event Frame Rx Sec Low */
> +#define GEM_PEFRN		0x01fc /* PTP Peer Event Frame Rx Ns */
> +#define GEM_PCSCTRL     0x0200 /* PCS control register*/
> +#define GEM_PCSSTATUS   0x0204 /* PCS Status*/
> +#define GEM_PCSANLPBASE 0x0214 /* PCS an lp base */
> +#define GEM_PFCSTATUS   0x026c /* PFC status*/
> +#define GEM_DCFG1		0x0280 /* Design Config 1 */
> +#define GEM_DCFG2		0x0284 /* Design Config 2 */
> +#define GEM_DCFG3		0x0288 /* Design Config 3 */
> +#define GEM_DCFG4		0x028c /* Design Config 4 */
> +#define GEM_DCFG5		0x0290 /* Design Config 5 */
> +#define GEM_DCFG6		0x0294 /* Design Config 6 */
> +#define GEM_DCFG7		0x0298 /* Design Config 7 */
> +#define GEM_DCFG8		0x029C /* Design Config 8 */
> +#define GEM_DCFG10		0x02A4 /* Design Config 10 */
> +
> +
> +#define GEM_TXBDCTRL	0x04cc /* TX Buffer Descriptor control register */
> +#define GEM_RXBDCTRL	0x04d0 /* RX Buffer Descriptor control register */
> +
> +/* Screener Type 2 match registers */
> +#define GEM_SCRT2		0x540
> +
> +/* EtherType registers */
> +#define GEM_ETHT		0x06E0
> +
> +/* Type 2 compare registers */
> +#define GEM_T2CMPW0		0x0700
> +#define GEM_T2CMPW1		0x0704
> +#define T2CMP_OFST(t2idx)	((t2idx) * 2)
> +
> +/* type 2 compare registers
> + * each location requires 3 compare regs
> + */
> +#define GEM_IP4SRC_CMP(idx)		((idx) * 3)
> +#define GEM_IP4DST_CMP(idx)		((idx) * 3 + 1)
> +#define GEM_PORT_CMP(idx)		((idx) * 3 + 2)
> +
> +/* Which screening type 2 EtherType register will be used (0 - 7) */
> +#define SCRT2_ETHT		0
> +
> +#define GEM_ISR(hw_q)		(0x0400 + ((hw_q) << 2))
> +#define GEM_TBQP(hw_q)		(0x0440 + ((hw_q) << 2))
> +#define GEM_TBQPH(hw_q)		(0x04C8)
> +#define GEM_RBQP(hw_q)		(0x0480 + ((hw_q) << 2))
> +#define GEM_RBQS(hw_q)		(0x04A0 + ((hw_q) << 2))
> +#define GEM_RBQPH(hw_q)		(0x04D4)
> +#define GEM_IER(hw_q)		(0x0600 + ((hw_q) << 2))
> +#define GEM_IDR(hw_q)		(0x0620 + ((hw_q) << 2))
> +#define GEM_IMR(hw_q)		(0x0640 + ((hw_q) << 2))
> +#define GEM_TXTAIL_ADDR(hw_q)		(0x0e80 + ((hw_q) << 2))
> +
> +#define GEM_USX_CONTROL         0x0A80  /* High speed PCS control register */
> +#define GEM_USX_STATUS          0x0A88 /* High speed PCS status register */
> +#define GEM_USX_FECERRCNT       0x0AD0 /* usx fec error counter */
> +
> +#define GEM_SRC_SEL_LN          0x1C04
> +#define GEM_DIV_SEL0_LN         0x1C08
> +#define GEM_DIV_SEL1_LN         0x1C0C
> +#define GEM_PMA_XCVR_POWER_STATE  0x1C10
> +#define GEM_SPEED_MODE          0x1C14
> +#define GEM_MII_SELECT          0x1C18
> +#define GEM_SEL_MII_ON_RGMII    0x1C1C
> +#define GEM_TX_CLK_SEL0         0x1C20
> +#define GEM_TX_CLK_SEL1         0x1C24
> +#define GEM_TX_CLK_SEL2         0x1C28
> +#define GEM_TX_CLK_SEL3         0x1C2C
> +#define GEM_RX_CLK_SEL0         0x1C30
> +#define GEM_RX_CLK_SEL1         0x1C34
> +#define GEM_CLK_250M_DIV10_DIV100_SEL 0x1C38
> +#define GEM_TX_CLK_SEL5         0x1C3C
> +#define GEM_TX_CLK_SEL6         0x1C40
> +#define GEM_RX_CLK_SEL4         0x1C44
> +#define GEM_RX_CLK_SEL5         0x1C48
> +#define GEM_TX_CLK_SEL3_0       0x1C70
> +#define GEM_TX_CLK_SEL4_0         0x1C74
> +#define GEM_RX_CLK_SEL3_0         0x1C78
> +#define GEM_RX_CLK_SEL4_0         0x1C7C
> +#define GEM_RGMII_TX_CLK_SEL0     0x1C80
> +#define GEM_RGMII_TX_CLK_SEL1     0x1C84
> +
> +#define GEM_PHY_INT_ENABLE        0x1C88
> +#define GEM_PHY_INT_CLEAR         0x1C8C
> +#define GEM_PHY_INT_STATE         0x1C90
> +
> +#define GEM_INTX_IRQ_MASK         0x1C14
> +
> +/* Bitfields in NCR */
> +#define MACB_LB_OFFSET		0 /* reserved */
> +#define MACB_LB_SIZE		1
> +#define MACB_LLB_OFFSET		1 /* Loop back local */
> +#define MACB_LLB_SIZE		1
> +#define MACB_RE_OFFSET		2 /* Receive enable */
> +#define MACB_RE_SIZE		1
> +#define MACB_TE_OFFSET		3 /* Transmit enable */
> +#define MACB_TE_SIZE		1
> +#define MACB_MPE_OFFSET		4 /* Management port enable */
> +#define MACB_MPE_SIZE		1
> +#define MACB_CLRSTAT_OFFSET	5 /* Clear stats regs */
> +#define MACB_CLRSTAT_SIZE	1
> +#define MACB_INCSTAT_OFFSET	6 /* Incremental stats regs */
> +#define MACB_INCSTAT_SIZE	1
> +#define MACB_WESTAT_OFFSET	7 /* Write enable stats regs */
> +#define MACB_WESTAT_SIZE	1
> +#define MACB_BP_OFFSET		8 /* Back pressure */
> +#define MACB_BP_SIZE		1
> +#define MACB_TSTART_OFFSET	9 /* Start transmission */
> +#define MACB_TSTART_SIZE	1
> +#define MACB_THALT_OFFSET	10 /* Transmit halt */
> +#define MACB_THALT_SIZE		1
> +#define MACB_NCR_TPF_OFFSET	11 /* Transmit pause frame */
> +#define MACB_NCR_TPF_SIZE	1
> +#define MACB_TZQ_OFFSET		12 /* Transmit zero quantum pause frame */
> +#define MACB_TZQ_SIZE		1
> +#define MACB_SRTSM_OFFSET	15
> +#define MACB_OSSMODE_OFFSET 24 /* Enable One Step Synchro Mode */
> +#define MACB_OSSMODE_SIZE	1
> +#define MACB_PFC_OFFSET     25 /* Enable PFC */
> +#define MACB_PFC_SIZE       1
> +#define MACB_RGMII_OFFSET   28
> +#define MACB_RGMII_SIZE     1
> +#define MACB_2PT5G_OFFSET   29
> +#define MACB_2PT5G_SIZE     1
> +#define MACB_HSMAC_OFFSET   31 /* Use high speed MAC */
> +#define MACB_HSMAC_SIZE     1
> +
> +/* GEM specific NCR bitfields. */
> +#define GEM_ENABLE_HS_MAC_OFFSET 31 /* Use high speed MAC */
> +#define GEM_ENABLE_HS_MAC_SIZE	1
> +
> +
> +/* Bitfields in NCFGR */
> +#define MACB_SPD_OFFSET		0 /* Speed */
> +#define MACB_SPD_SIZE		1
> +#define MACB_FD_OFFSET		1 /* Full duplex */
> +#define MACB_FD_SIZE		1
> +#define MACB_BIT_RATE_OFFSET	2 /* Discard non-VLAN frames */
> +#define MACB_BIT_RATE_SIZE	1
> +#define MACB_JFRAME_OFFSET	3 /* reserved */
> +#define MACB_JFRAME_SIZE	1
> +#define MACB_CAF_OFFSET		4 /* Copy all frames */
> +#define MACB_CAF_SIZE		1
> +#define MACB_NBC_OFFSET		5 /* No broadcast */
> +#define MACB_NBC_SIZE		1
> +#define MACB_NCFGR_MTI_OFFSET	6 /* Multicast hash enable */
> +#define MACB_NCFGR_MTI_SIZE	1
> +#define MACB_UNI_OFFSET		7 /* Unicast hash enable */
> +#define MACB_UNI_SIZE		1
> +#define MACB_BIG_OFFSET		8 /* Receive 1536 byte frames */
> +#define MACB_BIG_SIZE		1
> +#define MACB_EAE_OFFSET		9 /* External address match enable */
> +#define MACB_EAE_SIZE		1
> +#define MACB_CLK_OFFSET		10
> +#define MACB_CLK_SIZE		2
> +#define MACB_RTY_OFFSET		12 /* Retry test */
> +#define MACB_RTY_SIZE		1
> +#define MACB_PAE_OFFSET		13 /* Pause enable */
> +#define MACB_PAE_SIZE		1
> +#define MACB_RM9200_RMII_OFFSET	13 /* AT91RM9200 only */
> +#define MACB_RM9200_RMII_SIZE	1  /* AT91RM9200 only */
> +#define MACB_RBOF_OFFSET	14 /* Receive buffer offset */
> +#define MACB_RBOF_SIZE		2
> +#define MACB_RLCE_OFFSET	16 /* Length field error frame discard */
> +#define MACB_RLCE_SIZE		1
> +#define MACB_DRFCS_OFFSET	17 /* FCS remove */
> +#define MACB_DRFCS_SIZE		1
> +#define MACB_EFRHD_OFFSET	18
> +#define MACB_EFRHD_SIZE		1
> +#define MACB_IRXFCS_OFFSET	19
> +#define MACB_IRXFCS_SIZE	1
> +
> +/* GEM specific NCFGR bitfields. */
> +#define GEM_GBE_OFFSET		10 /* Gigabit mode enable */
> +#define GEM_GBE_SIZE		1
> +#define GEM_PCSSEL_OFFSET	11
> +#define GEM_PCSSEL_SIZE		1
> +#define GEM_CLK_OFFSET		18 /* MDC clock division */
> +#define GEM_CLK_SIZE		3
> +#define GEM_DBW_OFFSET		21 /* Data bus width */
> +#define GEM_DBW_SIZE		2
> +#define GEM_RXCOEN_OFFSET	24
> +#define GEM_RXCOEN_SIZE		1
> +#define GEM_SGMIIEN_OFFSET	27
> +#define GEM_SGMIIEN_SIZE	1
> +
> +
> +/* Constants for data bus width. */
> +#define GEM_DBW32		0 /* 32 bit AMBA AHB data bus width */
> +#define GEM_DBW64		1 /* 64 bit AMBA AHB data bus width */
> +#define GEM_DBW128		2 /* 128 bit AMBA AHB data bus width */
> +
> +/* Bitfields in DMACFG. */
> +#define GEM_FBLDO_OFFSET	0 /* fixed burst length for DMA */
> +#define GEM_FBLDO_SIZE		5
> +#define GEM_ENDIA_DESC_OFFSET	6 /* endian swap mode for management descriptor access */
> +#define GEM_ENDIA_DESC_SIZE	1
> +#define GEM_ENDIA_PKT_OFFSET	7 /* endian swap mode for packet data access */
> +#define GEM_ENDIA_PKT_SIZE	1
> +#define GEM_RXBMS_OFFSET	8 /* RX packet buffer memory size select */
> +#define GEM_RXBMS_SIZE		2
> +#define GEM_TXPBMS_OFFSET	10 /* TX packet buffer memory size select */
> +#define GEM_TXPBMS_SIZE		1
> +#define GEM_TXCOEN_OFFSET	11 /* TX IP/TCP/UDP checksum gen offload */
> +#define GEM_TXCOEN_SIZE		1
> +#define GEM_RXBS_OFFSET		16 /* DMA receive buffer size */
> +#define GEM_RXBS_SIZE		8
> +#define GEM_DDRP_OFFSET		24 /* disc_when_no_ahb */
> +#define GEM_DDRP_SIZE		1
> +#define GEM_RXEXT_OFFSET	28 /* RX extended Buffer Descriptor mode */
> +#define GEM_RXEXT_SIZE		1
> +#define GEM_TXEXT_OFFSET	29 /* TX extended Buffer Descriptor mode */
> +#define GEM_TXEXT_SIZE		1
> +#define GEM_ADDR64_OFFSET	30 /* Address bus width - 64b or 32b */
> +#define GEM_ADDR64_SIZE		1
> +
> +
> +/* Bitfields in NSR */
> +#define MACB_NSR_LINK_OFFSET	0 /* pcs_link_state */
> +#define MACB_NSR_LINK_SIZE	1
> +#define MACB_MDIO_OFFSET	1 /* status of the mdio_in pin */
> +#define MACB_MDIO_SIZE		1
> +#define MACB_IDLE_OFFSET	2 /* The PHY management logic is idle */
> +#define MACB_IDLE_SIZE		1
> +
> +/* Bitfields in TSR */
> +#define MACB_UBR_OFFSET		0 /* Used bit read */
> +#define MACB_UBR_SIZE		1
> +#define MACB_COL_OFFSET		1 /* Collision occurred */
> +#define MACB_COL_SIZE		1
> +#define MACB_TSR_RLE_OFFSET	2 /* Retry limit exceeded */
> +#define MACB_TSR_RLE_SIZE	1
> +#define MACB_TGO_OFFSET		3 /* Transmit go */
> +#define MACB_TGO_SIZE		1
> +#define MACB_BEX_OFFSET		4 /* TX frame corruption due to AHB error */
> +#define MACB_BEX_SIZE		1
> +#define MACB_RM9200_BNQ_OFFSET	4 /* AT91RM9200 only */
> +#define MACB_RM9200_BNQ_SIZE	1 /* AT91RM9200 only */
> +#define MACB_COMP_OFFSET	5 /* Transmit complete */
> +#define MACB_COMP_SIZE		1
> +#define MACB_UND_OFFSET		6 /* Transmit under run */
> +#define MACB_UND_SIZE		1
> +
> +/* Bitfields in RSR */
> +#define MACB_BNA_OFFSET		0 /* Buffer not available */
> +#define MACB_BNA_SIZE		1
> +#define MACB_REC_OFFSET		1 /* Frame received */
> +#define MACB_REC_SIZE		1
> +#define MACB_OVR_OFFSET		2 /* Receive overrun */
> +#define MACB_OVR_SIZE		1
> +
> +/* Bitfields in ISR/IER/IDR/IMR */
> +#define MACB_MFD_OFFSET		0 /* Management frame sent */
> +#define MACB_MFD_SIZE		1
> +#define MACB_RCOMP_OFFSET	1 /* Receive complete */
> +#define MACB_RCOMP_SIZE		1
> +#define MACB_RXUBR_OFFSET	2 /* RX used bit read */
> +#define MACB_RXUBR_SIZE		1
> +#define MACB_TXUBR_OFFSET	3 /* TX used bit read */
> +#define MACB_TXUBR_SIZE		1
> +#define MACB_ISR_TUND_OFFSET	4 /* Enable TX buffer under run interrupt */
> +#define MACB_ISR_TUND_SIZE	1
> +#define MACB_ISR_RLE_OFFSET	5 /* EN retry exceeded/late coll interrupt */
> +#define MACB_ISR_RLE_SIZE	1
> +#define MACB_TXERR_OFFSET	6 /* EN TX frame corrupt from error interrupt */
> +#define MACB_TXERR_SIZE		1
> +#define MACB_TCOMP_OFFSET	7 /* Enable transmit complete interrupt */
> +#define MACB_TCOMP_SIZE		1
> +#define MACB_ISR_LINK_OFFSET	9 /* Enable link change interrupt */
> +#define MACB_ISR_LINK_SIZE	1
> +#define MACB_ISR_ROVR_OFFSET	10 /* Enable receive overrun interrupt */
> +#define MACB_ISR_ROVR_SIZE	1
> +#define MACB_HRESP_OFFSET	11 /* Enable hrsep not OK interrupt */
> +#define MACB_HRESP_SIZE		1
> +#define MACB_PFR_OFFSET		12 /* Enable pause frame w/ quantum interrupt */
> +#define MACB_PFR_SIZE		1
> +#define MACB_PTZ_OFFSET		13 /* Enable pause time zero interrupt */
> +#define MACB_PTZ_SIZE		1
> +#define MACB_WOL_OFFSET		14 /* Enable wake-on-lan interrupt */
> +#define MACB_WOL_SIZE		1
> +#define MACB_DRQFR_OFFSET	18 /* PTP Delay Request Frame Received */
> +#define MACB_DRQFR_SIZE		1
> +#define MACB_SFR_OFFSET		19 /* PTP Sync Frame Received */
> +#define MACB_SFR_SIZE		1
> +#define MACB_DRQFT_OFFSET	20 /* PTP Delay Request Frame Transmitted */
> +#define MACB_DRQFT_SIZE		1
> +#define MACB_SFT_OFFSET		21 /* PTP Sync Frame Transmitted */
> +#define MACB_SFT_SIZE		1
> +#define MACB_PDRQFR_OFFSET	22 /* PDelay Request Frame Received */
> +#define MACB_PDRQFR_SIZE	1
> +#define MACB_PDRSFR_OFFSET	23 /* PDelay Response Frame Received */
> +#define MACB_PDRSFR_SIZE	1
> +#define MACB_PDRQFT_OFFSET	24 /* PDelay Request Frame Transmitted */
> +#define MACB_PDRQFT_SIZE	1
> +#define MACB_PDRSFT_OFFSET	25 /* PDelay Response Frame Transmitted */
> +#define MACB_PDRSFT_SIZE	1
> +#define MACB_SRI_OFFSET		26 /* TSU Seconds Register Increment */
> +#define MACB_SRI_SIZE		1
> +
> +/* Timer increment fields */
> +#define MACB_TI_CNS_OFFSET	0
> +#define MACB_TI_CNS_SIZE	8
> +#define MACB_TI_ACNS_OFFSET	8
> +#define MACB_TI_ACNS_SIZE	8
> +#define MACB_TI_NIT_OFFSET	16
> +#define MACB_TI_NIT_SIZE	8
> +
> +/* Bitfields in MAN */
> +#define MACB_DATA_OFFSET	0 /* data */
> +#define MACB_DATA_SIZE		16
> +#define MACB_CODE_OFFSET	16 /* Must be written to 10 */
> +#define MACB_CODE_SIZE		2
> +#define MACB_REGA_OFFSET	18 /* Register address */
> +#define MACB_REGA_SIZE		5
> +#define MACB_PHYA_OFFSET	23 /* PHY address */
> +#define MACB_PHYA_SIZE		5
> +#define MACB_RW_OFFSET		28 /* Operation. 10 is read. 01 is write. */
> +#define MACB_RW_SIZE		2
> +#define MACB_SOF_OFFSET		30 /* Must be written to 1 for Clause 22 */
> +#define MACB_SOF_SIZE		2
> +
> +/* Bitfields in USRIO (AVR32) */
> +#define MACB_MII_OFFSET				0
> +#define MACB_MII_SIZE				1
> +#define MACB_EAM_OFFSET				1
> +#define MACB_EAM_SIZE				1
> +#define MACB_TX_PAUSE_OFFSET			2
> +#define MACB_TX_PAUSE_SIZE			1
> +#define MACB_TX_PAUSE_ZERO_OFFSET		3
> +#define MACB_TX_PAUSE_ZERO_SIZE			1
> +
> +/* Bitfields in USRIO (AT91) */
> +#define MACB_RMII_OFFSET			0
> +#define MACB_RMII_SIZE				1
> +#define GEM_RGMII_OFFSET			0 /* GEM gigabit mode */
> +#define GEM_RGMII_SIZE				1
> +#define MACB_CLKEN_OFFSET			1
> +#define MACB_CLKEN_SIZE				1
> +
> +/* Bitfields in WOL */
> +#define MACB_IP_OFFSET				0
> +#define MACB_IP_SIZE				16
> +#define MACB_MAG_OFFSET				16
> +#define MACB_MAG_SIZE				1
> +#define MACB_ARP_OFFSET				17
> +#define MACB_ARP_SIZE				1
> +#define MACB_SA1_OFFSET				18
> +#define MACB_SA1_SIZE				1
> +#define MACB_WOL_MTI_OFFSET			19
> +#define MACB_WOL_MTI_SIZE			1
> +
> +/* Bitfields in MID */
> +#define MACB_IDNUM_OFFSET			16
> +#define MACB_IDNUM_SIZE				12
> +#define MACB_REV_OFFSET				0
> +#define MACB_REV_SIZE				16
> +
> +/* Bitfields in DCFG1. */
> +#define GEM_IRQCOR_OFFSET			23
> +#define GEM_IRQCOR_SIZE				1
> +#define GEM_DBWDEF_OFFSET			25
> +#define GEM_DBWDEF_SIZE				3
> +
> +/* Bitfields in DCFG2. */
> +#define GEM_RX_PKT_BUFF_OFFSET			20
> +#define GEM_RX_PKT_BUFF_SIZE			1
> +#define GEM_TX_PKT_BUFF_OFFSET			21
> +#define GEM_TX_PKT_BUFF_SIZE			1
> +
> +
> +/* Bitfields in DCFG5. */
> +#define GEM_TSU_OFFSET				8
> +#define GEM_TSU_SIZE				1
> +
> +/* Bitfields in DCFG6. */
> +#define GEM_PBUF_LSO_OFFSET			27
> +#define GEM_PBUF_LSO_SIZE			1
> +#define GEM_DAW64_OFFSET			23
> +#define GEM_DAW64_SIZE				1
> +
> +/* Bitfields in DCFG8. */
> +#define GEM_T1SCR_OFFSET			24
> +#define GEM_T1SCR_SIZE				8
> +#define GEM_T2SCR_OFFSET			16
> +#define GEM_T2SCR_SIZE				8
> +#define GEM_SCR2ETH_OFFSET			8
> +#define GEM_SCR2ETH_SIZE			8
> +#define GEM_SCR2CMP_OFFSET			0
> +#define GEM_SCR2CMP_SIZE			8
> +
> +/* Bitfields in DCFG10 */
> +#define GEM_TXBD_RDBUFF_OFFSET			12
> +#define GEM_TXBD_RDBUFF_SIZE			4
> +#define GEM_RXBD_RDBUFF_OFFSET			8
> +#define GEM_RXBD_RDBUFF_SIZE			4
> +
> +/* Bitfields in TISUBN */
> +#define GEM_SUBNSINCR_OFFSET			0
> +#define GEM_SUBNSINCR_SIZE			24
> +#define GEM_SUBNSINCRL_OFFSET			24
> +#define GEM_SUBNSINCRL_SIZE			8
> +#define GEM_SUBNSINCRH_OFFSET			0
> +#define GEM_SUBNSINCRH_SIZE			16
> +
> +/* Bitfields in TI */
> +#define GEM_NSINCR_OFFSET			0
> +#define GEM_NSINCR_SIZE				8
> +
> +/* Bitfields in TSH */
> +/* TSU timer value (s). MSB [47:32] of seconds timer count */
> +#define GEM_TSH_OFFSET				0
> +#define GEM_TSH_SIZE				16
> +
> +/* Bitfields in TSL */
> +/* TSU timer value (s). LSB [31:0] of seconds timer count */
> +#define GEM_TSL_OFFSET				0
> +#define GEM_TSL_SIZE				32
> +
> +/* Bitfields in TN */
> +#define GEM_TN_OFFSET				0 /* TSU timer value (ns) */
> +#define GEM_TN_SIZE				30
> +
> +/* Bitfields in TXBDCTRL */
> +#define GEM_TXTSMODE_OFFSET			4 /* TX Descriptor Timestamp Insertion mode */
> +#define GEM_TXTSMODE_SIZE			2
> +
> +/* Bitfields in RXBDCTRL */
> +#define GEM_RXTSMODE_OFFSET			4 /* RX Descriptor Timestamp Insertion mode */
> +#define GEM_RXTSMODE_SIZE			2
> +
> +/* Bitfields in SCRT2 */
> +#define GEM_QUEUE_OFFSET			0 /* Queue Number */
> +#define GEM_QUEUE_SIZE				4
> +#define GEM_VLANPR_OFFSET			4 /* VLAN Priority */
> +#define GEM_VLANPR_SIZE				3
> +#define GEM_VLANEN_OFFSET			8 /* VLAN Enable */
> +#define GEM_VLANEN_SIZE				1
> +#define GEM_ETHT2IDX_OFFSET			9 /* Index to screener type 2 EtherType register */
> +#define GEM_ETHT2IDX_SIZE			3
> +#define GEM_ETHTEN_OFFSET			12 /* EtherType Enable */
> +#define GEM_ETHTEN_SIZE				1
> +/* Compare A - Index to screener type 2 Compare register */
> +#define GEM_CMPA_OFFSET				13
> +#define GEM_CMPA_SIZE				5
> +#define GEM_CMPAEN_OFFSET			18 /* Compare A Enable */
> +#define GEM_CMPAEN_SIZE				1
> +/* Compare B - Index to screener type 2 Compare register */
> +#define GEM_CMPB_OFFSET				19
> +#define GEM_CMPB_SIZE				5
> +#define GEM_CMPBEN_OFFSET			24 /* Compare B Enable */
> +#define GEM_CMPBEN_SIZE				1
> +/* Compare C - Index to screener type 2 Compare register */
> +#define GEM_CMPC_OFFSET				25
> +#define GEM_CMPC_SIZE				5
> +#define GEM_CMPCEN_OFFSET			30 /* Compare C Enable */
> +#define GEM_CMPCEN_SIZE				1
> +
> +/* Bitfields in ETHT */
> +#define GEM_ETHTCMP_OFFSET			0 /* EtherType compare value */
> +#define GEM_ETHTCMP_SIZE			16
> +
> +/* Bitfields in T2CMPW0 */
> +#define GEM_T2CMP_OFFSET			16 /* 0xFFFF0000 compare value */
> +#define GEM_T2CMP_SIZE				16
> +#define GEM_T2MASK_OFFSET			0 /* 0x0000FFFF compare value or mask */
> +#define GEM_T2MASK_SIZE				16
> +
> +/* Bitfields in T2CMPW1 */
> +#define GEM_T2DISMSK_OFFSET			9 /* disable mask */
> +#define GEM_T2DISMSK_SIZE			1
> +#define GEM_T2CMPOFST_OFFSET			7 /* compare offset */
> +#define GEM_T2CMPOFST_SIZE			2
> +#define GEM_T2OFST_OFFSET			0 /* offset value */
> +#define GEM_T2OFST_SIZE				7
> +
> +/* Offset for screener type 2 compare values (T2CMPOFST).
> + * Note the offset is applied after the specified point,
> + * e.g. GEM_T2COMPOFST_ETYPE denotes the EtherType field, so an offset
> + * of 12 bytes from this would be the source IP address in an IP header
> + */
> +#define GEM_T2COMPOFST_SOF	0
> +#define GEM_T2COMPOFST_ETYPE	1
> +#define GEM_T2COMPOFST_IPHDR	2
> +#define GEM_T2COMPOFST_TCPUDP	3
> +
> +/* offset from EtherType to IP address */
> +#define ETYPE_SRCIP_OFFSET			12
> +#define ETYPE_DSTIP_OFFSET			16
> +
> +/* offset from IP header to port */
> +#define IPHDR_SRCPORT_OFFSET		0
> +#define IPHDR_DSTPORT_OFFSET		2
> +
> +/* Transmit DMA buffer descriptor Word 1 */
> +/* timestamp has been captured in the Buffer Descriptor */
> +#define GEM_DMA_TXVALID_OFFSET		23
> +#define GEM_DMA_TXVALID_SIZE		1
> +
> +/* Receive DMA buffer descriptor Word 0 */
> +#define GEM_DMA_RXVALID_OFFSET		2 /* indicates a valid timestamp in the Buffer Descriptor */
> +#define GEM_DMA_RXVALID_SIZE		1
> +
> +/* DMA buffer descriptor Word 2 (32 bit addressing) or Word 4 (64 bit addressing) */
> +#define GEM_DMA_SECL_OFFSET			30 /* Timestamp seconds[1:0]  */
> +#define GEM_DMA_SECL_SIZE			2
> +#define GEM_DMA_NSEC_OFFSET			0 /* Timestamp nanosecs [29:0] */
> +#define GEM_DMA_NSEC_SIZE			30
> +
> +/* DMA buffer descriptor Word 3 (32 bit addressing) or Word 5 (64 bit addressing) */
> +
> +/* New hardware supports 12 bit precision of timestamp in DMA buffer descriptor.
> + * Old hardware supports only 6 bit precision but it is enough for PTP.
> + * Less accuracy is used always instead of checking hardware version.
> + */
> +#define GEM_DMA_SECH_OFFSET			0 /* Timestamp seconds[5:2] */
> +#define GEM_DMA_SECH_SIZE			4
> +#define GEM_DMA_SEC_WIDTH			(GEM_DMA_SECH_SIZE + GEM_DMA_SECL_SIZE)
> +#define GEM_DMA_SEC_TOP				(1 << GEM_DMA_SEC_WIDTH)
> +#define GEM_DMA_SEC_MASK			(GEM_DMA_SEC_TOP - 1)
> +
> +/* Bitfields in ADJ */
> +#define GEM_ADDSUB_OFFSET			31
> +#define GEM_ADDSUB_SIZE				1
> +/* Constants for CLK */
> +#define MACB_CLK_DIV8				0
> +#define MACB_CLK_DIV16				1
> +#define MACB_CLK_DIV32				2
> +#define MACB_CLK_DIV64				3
> +
> +/* GEM specific constants for CLK. */
> +#define GEM_CLK_DIV8				0
> +#define GEM_CLK_DIV16				1
> +#define GEM_CLK_DIV32				2
> +#define GEM_CLK_DIV48				3
> +#define GEM_CLK_DIV64				4
> +#define GEM_CLK_DIV96				5
> +#define GEM_CLK_DIV128              6
> +#define GEM_CLK_DIV224              7
> +
> +/* Constants for MAN register */
> +#define MACB_MAN_C22_SOF            1
> +#define MACB_MAN_C22_WRITE          1
> +#define MACB_MAN_C22_READ           2
> +#define MACB_MAN_C22_CODE           2
> +
> +#define MACB_MAN_C45_SOF            0
> +#define MACB_MAN_C45_ADDR           0
> +#define MACB_MAN_C45_WRITE          1
> +#define MACB_MAN_C45_POST_READ_INCR     2
> +#define MACB_MAN_C45_READ           3
> +#define MACB_MAN_C45_CODE           2
> +
> +/* Capability mask bits */
> +#define MACB_CAPS_ISR_CLEAR_ON_WRITE        0x00000001
> +#define MACB_CAPS_USRIO_HAS_CLKEN           0x00000002
> +#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII 0x00000004
> +#define MACB_CAPS_NO_GIGABIT_HALF           0x00000008
> +#define MACB_CAPS_USRIO_DISABLED            0x00000010
> +#define MACB_CAPS_JUMBO                     0x00000020
> +#define MACB_CAPS_GEM_HAS_PTP               0x00000040
> +#define MACB_CAPS_BD_RD_PREFETCH            0x00000080
> +#define MACB_CAPS_NEEDS_RSTONUBR            0x00000100
> +#define MACB_CAPS_SEL_CLK                   0x00000200
> +#define MACB_CAPS_PERFORMANCE_OPTIMIZING    0x00000400
> +#define MACB_CAPS_FIFO_MODE                 0x10000000
> +#define MACB_CAPS_GIGABIT_MODE_AVAILABLE    0x20000000
> +#define MACB_CAPS_SG_DISABLED               0x40000000
> +#define MACB_CAPS_MACB_IS_GEM               0x80000000
> +#define MACB_CAPS_SEL_CLK_HW                0x00001000
> +
> +
> +/*GEM PCS status register bitfields*/
> +#define GEM_LINKSTATUS_OFFSET    2
> +#define GEM_LINKSTATUS_SIZE      1
> +
> +/*GEM usx status register bitfields*/
> +#define GEM_BLOCK_LOCK_OFFSET    0
> +#define GEM_BLOCK_LOCK_SIZE      1
> +
> +
> +/*GEM hs mac config register bitfields*/
> +#define GEM_HSMACSPEED_OFFSET    0
> +#define GEM_HSMACSPEED_SIZE      3
> +/*GEM pcs_an_lp_base register bitfields*/
> +#define GEM_SGMIISPEED_OFFSET   10
> +#define GEM_SGMIISPEED_SIZE     2
> +#define GEM_SGMIIDUPLEX_OFFSET  12
> +#define GEM_SGMIIDUPLEX_SIZE    1
> +
> +/*GEM pcs control register bitfields*/
> +#define GEM_AUTONEG_OFFSET    12
> +#define GEM_AUTONEG_SIZE      1
> +/*pcs_an_lp_base register bitfields*/
> +#define GEM_SPEEDR_OFFSET 10
> +#define GEM_SPEEDR_SIZE   2
> +#define GEM_DUPLEX_OFFSET 12
> +#define GEM_DUPLEX_SIZE   1
> +
> +/* Bitfields in USX_CONTROL. */
> +#define GEM_SIGNAL_OK_OFFSET            0
> +#define GEM_SIGNAL_OK_SIZE              1
> +#define GEM_TX_EN_OFFSET                1
> +#define GEM_TX_EN_SIZE                  1
> +#define GEM_RX_SYNC_RESET_OFFSET        2
> +#define GEM_RX_SYNC_RESET_SIZE          1
> +#define GEM_FEC_ENABLE_OFFSET           4
> +#define GEM_FEC_ENABLE_SIZE             1
> +#define GEM_FEC_ENA_ERR_IND_OFFSET      5
> +#define GEM_FEC_ENA_ERR_IND_SIZE        1
> +#define GEM_TX_SCR_BYPASS_OFFSET        8
> +#define GEM_TX_SCR_BYPASS_SIZE          1
> +#define GEM_RX_SCR_BYPASS_OFFSET        9
> +#define GEM_RX_SCR_BYPASS_SIZE          1
> +#define GEM_SERDES_RATE_OFFSET          12
> +#define GEM_SERDES_RATE_SIZE            2
> +#define GEM_USX_CTRL_SPEED_OFFSET       14
> +#define GEM_USX_CTRL_SPEED_SIZE         3
> +
> +/* LSO settings */
> +#define MACB_LSO_UFO_ENABLE			0x01
> +#define MACB_LSO_TSO_ENABLE			0x02
> +
> +/* Bitfield in HS_MAC_CONFIG */
> +#define GEM_HS_MAC_SPEED_OFFSET			0
> +#define GEM_HS_MAC_SPEED_SIZE			3
> +
> +/* Bitfield in pcs control */
> +#define GEM_PCS_AUTO_NEG_ENB_OFFSET			12
> +#define GEM_PCS_AUTO_NEG_ENB_SIZE			1
> +
> +
> +/* USXGMII/SGMII/RGMII speed */
> +#define GEM_SPEED_100   0
> +#define GEM_SPEED_1000  1
> +#define GEM_SPEED_2500  2
> +#define GEM_SPEED_5000  3
> +#define GEM_SPEED_10000 4
> +#define GEM_SPEED_25000 5
> +#define MACB_SERDES_RATE_5G		0
> +#define MACB_SERDES_RATE_10G	1
> +
> +
> +/* Bit manipulation macros */
> +#define MACB_BIT(name)					\
> +	(1 << MACB_##name##_OFFSET)
> +#define MACB_BF(name, value)				\
> +	(((value) & ((1 << MACB_##name##_SIZE) - 1))	\
> +	 << MACB_##name##_OFFSET)
> +#define MACB_BFEXT(name, value)\
> +	(((value) >> MACB_##name##_OFFSET)		\
> +	 & ((1 << MACB_##name##_SIZE) - 1))
> +#define MACB_BFINS(name, value, old)			\
> +	(((old) & ~(((1 << MACB_##name##_SIZE) - 1)	\
> +		    << MACB_##name##_OFFSET))		\
> +	 | MACB_BF(name, value))
> +
> +#define GEM_BIT(name)					\
> +	(1 << GEM_##name##_OFFSET)
> +#define GEM_BF(name, value)				\
> +	(((value) & ((1 << GEM_##name##_SIZE) - 1))	\
> +	 << GEM_##name##_OFFSET)
> +#define GEM_BFEXT(name, value)\
> +	(((value) >> GEM_##name##_OFFSET)		\
> +	 & ((1 << GEM_##name##_SIZE) - 1))
> +#define GEM_BFINS(name, value, old)			\
> +	(((old) & ~(((1 << GEM_##name##_SIZE) - 1)	\
> +		    << GEM_##name##_OFFSET))		\
> +	 | GEM_BF(name, value))
> +
> +#define PTP_TS_BUFFER_SIZE		128 /* must be power of 2 */
> +
> +/* Conditional GEM/MACB macros.  These perform the operation to the correct
> + * register dependent on whether the device is a GEM or a MACB.  For registers
> + * and bitfields that are common across both devices, use macb_{read,write}l
> + * to avoid the cost of the conditional.
> + */
> +#define macb_or_gem_writel(__bp, __reg, __value) \
> +	({ \
> +		if (macb_is_gem((__bp))) \
> +			gem_writel((__bp), __reg, __value); \
> +		else \
> +			macb_writel((__bp), __reg, __value); \
> +	})
> +
> +#define macb_or_gem_readl(__bp, __reg) \
> +	({ \
> +		u32 __v; \
> +		if (macb_is_gem((__bp))) \
> +			__v = gem_readl((__bp), __reg); \
> +		else \
> +			__v = macb_readl((__bp), __reg); \
> +		__v; \
> +	})
> +
> +#ifdef MACB_EXT_DESC
> +#define HW_DMA_CAP_32B		0
> +#define HW_DMA_CAP_64B		(1 << 0)
> +#define HW_DMA_CAP_PTP		(1 << 1)
> +#define HW_DMA_CAP_64B_PTP	(HW_DMA_CAP_64B | HW_DMA_CAP_PTP)
> +#endif
> +
> +/* DMA descriptor bitfields */
> +#define MACB_RX_USED_OFFSET			0
> +#define MACB_RX_USED_SIZE			1
> +#define MACB_RX_WRAP_OFFSET			1
> +#define MACB_RX_WRAP_SIZE			1
> +#define MACB_RX_WADDR_OFFSET			2
> +#define MACB_RX_WADDR_SIZE			30
> +
> +#define MACB_RX_FRMLEN_OFFSET			0
> +#define MACB_RX_FRMLEN_SIZE			12
> +#define MACB_RX_OFFSET_OFFSET			12
> +#define MACB_RX_SOF_OFFSET			14
> +#define MACB_RX_OFFSET_SIZE			2
> +#define MACB_RX_SOF_SIZE			1
> +#define MACB_RX_EOF_OFFSET			15
> +#define MACB_RX_EOF_SIZE			1
> +#define MACB_RX_CFI_OFFSET			16
> +#define MACB_RX_CFI_SIZE			1
> +#define MACB_RX_VLAN_PRI_OFFSET			17
> +#define MACB_RX_VLAN_PRI_SIZE			3
> +#define MACB_RX_PRI_TAG_OFFSET			20
> +#define MACB_RX_PRI_TAG_SIZE			1
> +#define MACB_RX_VLAN_TAG_OFFSET			21
> +#define MACB_RX_VLAN_TAG_SIZE			1
> +#define MACB_RX_TYPEID_MATCH_OFFSET		22
> +#define MACB_RX_TYPEID_MATCH_SIZE		1
> +#define MACB_RX_SA4_MATCH_OFFSET		23
> +#define MACB_RX_SA4_MATCH_SIZE			1
> +#define MACB_RX_SA3_MATCH_OFFSET		24
> +#define MACB_RX_SA3_MATCH_SIZE			1
> +#define MACB_RX_SA2_MATCH_OFFSET		25
> +#define MACB_RX_SA2_MATCH_SIZE			1
> +#define MACB_RX_SA1_MATCH_OFFSET		26
> +#define MACB_RX_SA1_MATCH_SIZE			1
> +#define MACB_RX_EXT_MATCH_OFFSET		28
> +#define MACB_RX_EXT_MATCH_SIZE			1
> +#define MACB_RX_UHASH_MATCH_OFFSET		29
> +#define MACB_RX_UHASH_MATCH_SIZE		1
> +#define MACB_RX_MHASH_MATCH_OFFSET		30
> +#define MACB_RX_MHASH_MATCH_SIZE		1
> +#define MACB_RX_BROADCAST_OFFSET		31
> +#define MACB_RX_BROADCAST_SIZE			1
> +
> +#define MACB_RX_FRMLEN_MASK			0xFFF
> +#define MACB_RX_JFRMLEN_MASK			0x3FFF
> +
> +/* RX checksum offload disabled: bit 24 clear in NCFGR */
> +#define GEM_RX_TYPEID_MATCH_OFFSET		22
> +#define GEM_RX_TYPEID_MATCH_SIZE		2
> +
> +/* RX checksum offload enabled: bit 24 set in NCFGR */
> +#define GEM_RX_CSUM_OFFSET			22
> +#define GEM_RX_CSUM_SIZE			2
> +
> +#define MACB_TX_FRMLEN_OFFSET			0
> +#define MACB_TX_FRMLEN_SIZE			11
> +#define MACB_TX_LAST_OFFSET			15
> +#define MACB_TX_LAST_SIZE			1
> +#define MACB_TX_NOCRC_OFFSET			16
> +#define MACB_TX_NOCRC_SIZE			1
> +#define MACB_MSS_MFS_OFFSET			16
> +#define MACB_MSS_MFS_SIZE			14
> +#define MACB_TX_LSO_OFFSET			17
> +#define MACB_TX_LSO_SIZE			2
> +#define MACB_TX_TCP_SEQ_SRC_OFFSET		19
> +#define MACB_TX_TCP_SEQ_SRC_SIZE		1
> +#define MACB_TX_BUF_EXHAUSTED_OFFSET		27
> +#define MACB_TX_BUF_EXHAUSTED_SIZE		1
> +#define MACB_TX_UNDERRUN_OFFSET			28
> +#define MACB_TX_UNDERRUN_SIZE			1
> +#define MACB_TX_ERROR_OFFSET			29
> +#define MACB_TX_ERROR_SIZE			1
> +#define MACB_TX_WRAP_OFFSET			30
> +#define MACB_TX_WRAP_SIZE			1
> +#define MACB_TX_USED_OFFSET			31
> +#define MACB_TX_USED_SIZE			1
> +
> +#define GEM_TX_FRMLEN_OFFSET			0
> +#define GEM_TX_FRMLEN_SIZE			14
> +
> +/* Buffer descriptor constants */
> +#define GEM_RX_CSUM_NONE			0
> +#define GEM_RX_CSUM_IP_ONLY			1
> +#define GEM_RX_CSUM_IP_TCP			2
> +#define GEM_RX_CSUM_IP_UDP			3
> +
> +/* limit RX checksum offload to TCP and UDP packets */
> +#define GEM_RX_CSUM_CHECKED_MASK		2
> +
> +/* Hardware-collected statistics. Used when updating the network
> + * device stats by a periodic timer.
> + */
> +struct macb_stats {
> +	u64 rx_pause_frames;
> +	u64 tx_ok;
> +	u64 tx_single_cols;
> +	u64 tx_multiple_cols;
> +	u64 rx_ok;
> +	u64 rx_fcs_errors;
> +	u64 rx_align_errors;
> +	u64 tx_deferred;
> +	u64 tx_late_cols;
> +	u64 tx_excessive_cols;
> +	u64 tx_underruns;
> +	u64 tx_carrier_errors;
> +	u64 rx_resource_errors;
> +	u64 rx_overruns;
> +	u64 rx_symbol_errors;
> +	u64 rx_oversize_pkts;
> +	u64 rx_jabbers;
> +	u64 rx_undersize_pkts;
> +	u64 sqe_test_errors;
> +	u64 rx_length_mismatch;
> +	u64 tx_pause_frames;
> +};
> +
> +struct gem_stats {
> +	u64 tx_octets_31_0;
> +	u64 tx_octets_47_32;
> +	u64 tx_frames;
> +	u64 tx_broadcast_frames;
> +	u64 tx_multicast_frames;
> +	u64 tx_pause_frames;
> +	u64 tx_64_byte_frames;
> +	u64 tx_65_127_byte_frames;
> +	u64 tx_128_255_byte_frames;
> +	u64 tx_256_511_byte_frames;
> +	u64 tx_512_1023_byte_frames;
> +	u64 tx_1024_1518_byte_frames;
> +	u64 tx_greater_than_1518_bytes;
> +	u64 tx_underrun;
> +	u64 tx_single_collision_frames;
> +	u64 tx_multiple_collision_frames;
> +	u64 tx_excessive_collisions;
> +	u64 tx_late_collisions;
> +	u64 tx_deferred_frames;
> +	u64 tx_carrier_sense_errors;
> +	u64 rx_octets_31_0;
> +	u64 rx_octets_47_32;
> +	u64 rx_frames;
> +	u64 rx_broadcast_frames;
> +	u64 rx_multicast_frames;
> +	u64 rx_pause_frames;
> +	u64 rx_64_byte_frames;
> +	u64 rx_65_127_byte_frames;
> +	u64 rx_128_255_byte_frames;
> +	u64 rx_256_511_byte_frames;
> +	u64 rx_512_1023_byte_frames;
> +	u64 rx_1024_1518_byte_frames;
> +	u64 rx_greater_than_1518_bytes;
> +	u64 rx_undersized_frames;
> +	u64 rx_oversize_frames;
> +	u64 rx_jabbers;
> +	u64 rx_frame_check_sequence_errors;
> +	u64 rx_length_field_frame_errors;
> +	u64 rx_symbol_errors;
> +	u64 rx_alignment_errors;
> +	u64 rx_resource_drops;
> +	u64 rx_overruns;
> +	u64 rx_ip_header_checksum_errors;
> +	u64 rx_tcp_checksum_errors;
> +	u64 rx_udp_checksum_errors;
> +};
> +
> +/* Describes the name and offset of an individual statistic register, as
> + * returned by `ethtool -S`. Also describes which net_device_stats statistics
> + * this register should contribute to.
> + */
> +struct gem_statistic {
> +	char stat_string[ETH_GSTRING_LEN];
> +	int offset;
> +	u32 stat_bits;
> +};
> +
> +/* Bitfield defs for net_device_stat statistics */
> +#define GEM_NDS_RXERR_OFFSET		0
> +#define GEM_NDS_RXLENERR_OFFSET		1
> +#define GEM_NDS_RXOVERERR_OFFSET	2
> +#define GEM_NDS_RXCRCERR_OFFSET		3
> +#define GEM_NDS_RXFRAMEERR_OFFSET	4
> +#define GEM_NDS_RXFIFOERR_OFFSET	5
> +#define GEM_NDS_TXERR_OFFSET		6
> +#define GEM_NDS_TXABORTEDERR_OFFSET	7
> +#define GEM_NDS_TXCARRIERERR_OFFSET	8
> +#define GEM_NDS_TXFIFOERR_OFFSET	9
> +#define GEM_NDS_COLLISIONS_OFFSET	10
> +
> +#define GEM_STAT_TITLE(name, title) GEM_STAT_TITLE_BITS(name, title, 0)
> +#define GEM_STAT_TITLE_BITS(name, title, bits) {	\
> +	.stat_string = title,				\
> +	.offset = GEM_##name,				\
> +	.stat_bits = bits				\
> +}
> +
> +/* list of gem statistic registers. The names MUST match the
> + * corresponding GEM_* definitions.
> + */
> +static const struct gem_statistic gem_statistics[] = {
> +	GEM_STAT_TITLE(OCTTXL, "tx_octets"), /* OCTTXH combined with OCTTXL */
> +	GEM_STAT_TITLE(TXCNT, "tx_frames"),
> +	GEM_STAT_TITLE(TXBCCNT, "tx_broadcast_frames"),
> +	GEM_STAT_TITLE(TXMCCNT, "tx_multicast_frames"),
> +	GEM_STAT_TITLE(TXPAUSECNT, "tx_pause_frames"),
> +	GEM_STAT_TITLE(TX64CNT, "tx_64_byte_frames"),
> +	GEM_STAT_TITLE(TX65CNT, "tx_65_127_byte_frames"),
> +	GEM_STAT_TITLE(TX128CNT, "tx_128_255_byte_frames"),
> +	GEM_STAT_TITLE(TX256CNT, "tx_256_511_byte_frames"),
> +	GEM_STAT_TITLE(TX512CNT, "tx_512_1023_byte_frames"),
> +	GEM_STAT_TITLE(TX1024CNT, "tx_1024_1518_byte_frames"),
> +	GEM_STAT_TITLE(TX1519CNT, "tx_greater_than_1518_bytes"),
> +	GEM_STAT_TITLE_BITS(TXURUNCNT, "tx_underrun",
> +			    GEM_BIT(NDS_TXERR) | GEM_BIT(NDS_TXFIFOERR)),
> +	GEM_STAT_TITLE_BITS(SNGLCOLLCNT, "tx_single_collision_frames",
> +			    GEM_BIT(NDS_TXERR) | GEM_BIT(NDS_COLLISIONS)),
> +	GEM_STAT_TITLE_BITS(MULTICOLLCNT, "tx_multiple_collision_frames",
> +			    GEM_BIT(NDS_TXERR) | GEM_BIT(NDS_COLLISIONS)),
> +	GEM_STAT_TITLE_BITS(EXCESSCOLLCNT, "tx_excessive_collisions", GEM_BIT(NDS_TXERR) |
> +			    GEM_BIT(NDS_TXABORTEDERR) | GEM_BIT(NDS_COLLISIONS)),
> +	GEM_STAT_TITLE_BITS(LATECOLLCNT, "tx_late_collisions",
> +			    GEM_BIT(NDS_TXERR) | GEM_BIT(NDS_COLLISIONS)),
> +	GEM_STAT_TITLE(TXDEFERCNT, "tx_deferred_frames"),
> +	GEM_STAT_TITLE_BITS(TXCSENSECNT, "tx_carrier_sense_errors",
> +			    GEM_BIT(NDS_TXERR) | GEM_BIT(NDS_COLLISIONS)),
> +	GEM_STAT_TITLE(OCTRXL, "rx_octets"), /* OCTRXH combined with OCTRXL */
> +	GEM_STAT_TITLE(RXCNT, "rx_frames"),
> +	GEM_STAT_TITLE(RXBROADCNT, "rx_broadcast_frames"),
> +	GEM_STAT_TITLE(RXMULTICNT, "rx_multicast_frames"),
> +	GEM_STAT_TITLE(RXPAUSECNT, "rx_pause_frames"),
> +	GEM_STAT_TITLE(RX64CNT, "rx_64_byte_frames"),
> +	GEM_STAT_TITLE(RX65CNT, "rx_65_127_byte_frames"),
> +	GEM_STAT_TITLE(RX128CNT, "rx_128_255_byte_frames"),
> +	GEM_STAT_TITLE(RX256CNT, "rx_256_511_byte_frames"),
> +	GEM_STAT_TITLE(RX512CNT, "rx_512_1023_byte_frames"),
> +	GEM_STAT_TITLE(RX1024CNT, "rx_1024_1518_byte_frames"),
> +	GEM_STAT_TITLE(RX1519CNT, "rx_greater_than_1518_bytes"),
> +	GEM_STAT_TITLE_BITS(RXUNDRCNT, "rx_undersized_frames",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXLENERR)),
> +	GEM_STAT_TITLE_BITS(RXOVRCNT, "rx_oversize_frames",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXLENERR)),
> +	GEM_STAT_TITLE_BITS(RXJABCNT, "rx_jabbers", GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXLENERR)),
> +	GEM_STAT_TITLE_BITS(RXFCSCNT, "rx_frame_check_sequence_errors",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXCRCERR)),
> +	GEM_STAT_TITLE_BITS(RXLENGTHCNT, "rx_length_field_frame_errors", GEM_BIT(NDS_RXERR)),
> +	GEM_STAT_TITLE_BITS(RXSYMBCNT, "rx_symbol_errors",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXFRAMEERR)),
> +	GEM_STAT_TITLE_BITS(RXALIGNCNT, "rx_alignment_errors",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXOVERERR)),
> +	GEM_STAT_TITLE_BITS(RXRESERRCNT, "rx_resource_errors",
> +			    GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXOVERERR)),
> +	GEM_STAT_TITLE_BITS(RXORCNT, "rx_overruns", GEM_BIT(NDS_RXERR) | GEM_BIT(NDS_RXFIFOERR)),
> +	GEM_STAT_TITLE_BITS(RXIPCCNT, "rx_ip_header_checksum_errors", GEM_BIT(NDS_RXERR)),
> +	GEM_STAT_TITLE_BITS(RXTCPCCNT, "rx_tcp_checksum_errors", GEM_BIT(NDS_RXERR)),
> +	GEM_STAT_TITLE_BITS(RXUDPCCNT, "rx_udp_checksum_errors", GEM_BIT(NDS_RXERR)),
> +};
> +
> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
> +
> +#define GEM_STATS_LEN ARRAY_SIZE(gem_statistics)
> +
> +#define QUEUE_STAT_TITLE(title) {	\
> +	.stat_string = title,			\
> +}
> +
> +#define QUEUE_STATS_LEN ARRAY_SIZE(queue_statistics)
> +
> +#ifdef CONFIG_MACB_USE_HWSTAMP
> +#define GEM_TSEC_SIZE  (GEM_TSH_SIZE + GEM_TSL_SIZE)
> +#define TSU_SEC_MAX_VAL (((u64)1 << GEM_TSEC_SIZE) - 1)
> +#define TSU_NSEC_MAX_VAL ((1 << GEM_TN_SIZE) - 1)
> +
> +enum macb_bd_control {
> +	TSTAMP_DISABLED,
> +	TSTAMP_FRAME_PTP_EVENT_ONLY,
> +	TSTAMP_ALL_PTP_FRAMES,
> +	TSTAMP_ALL_FRAMES,
> +};
> +
> +/* Register access macros */
> +#define readl_relaxed(c)	({ u32 __r = le32_tc_cpu((__force __le32)__raw_readl(c)); __r; })
> +
> +#endif /* CONFIG_MACB_USE_HWSTAMP */
> +
> +#endif /* _MACB_H */
> diff --git a/drivers/net/macb/base/macb_type.h b/drivers/net/macb/base/macb_type.h
> new file mode 100644
> index 0000000..326c614
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_type.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_TYPE_H_
> +#define _MACB_TYPE_H_
> +
> +#include <stdint.h>
> +#include <inttypes.h>
> +
> +typedef uint8_t     u8;
> +typedef uint16_t    u16;
> +typedef uint32_t    u32;
> +typedef uint64_t    u64;
> +typedef int8_t      s8;
> +typedef int16_t     s16;
> +typedef int32_t     s32;
> +typedef int64_t     s64;
> +
> +typedef u64 dma_addr_t;
> +typedef u64 phys_addr_t;
> +
> +#endif /* _MACB_TYPE_H */
> diff --git a/drivers/net/macb/base/macb_uio.c b/drivers/net/macb/base/macb_uio.c
> new file mode 100644
> index 0000000..19b757d
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_uio.c
> @@ -0,0 +1,351 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +#include <dirent.h>
> +
> +#include "macb_uio.h"
> +
> +#define MACB_UIO_DRV_DIR "/sys/bus/platform/drivers/macb_uio"
> +#define UIO_DEV_DIR "/sys/class/uio"
> +
> +static int udev_id_from_filename(char *name)
> +{
> +	enum scan_states { ss_u, ss_i, ss_o, ss_num, ss_err };
> +	enum scan_states state = ss_u;
> +	int i = 0, num = -1;
> +	char ch = name[0];
> +	while (ch && (state != ss_err)) {
> +		switch (ch) {
> +		case 'u':
> +			if (state == ss_u)
> +				state = ss_i;
> +			else
> +				state = ss_err;
> +			break;
> +		case 'i':
> +			if (state == ss_i)
> +				state = ss_o;
> +			else
> +				state = ss_err;
> +			break;
> +		case 'o':
> +			if (state == ss_o)
> +				state = ss_num;
> +			else
> +				state = ss_err;
> +			break;
> +		default:
> +			if ((ch >= '0') && (ch <= '9') && state == ss_num) {
> +				if (num < 0)
> +					num = (ch - '0');
> +				else
> +					num = (num * 10) + (ch - '0');
> +			} else {
> +				state = ss_err;
> +			}
> +		}
> +		i++;
> +		ch = name[i];
> +	}
> +	if (state == ss_err)
> +		num = -1;
> +	return num;
> +}
> +
> +static int line_buf_from_filename(char *filename, char *linebuf)
> +{
> +	char *s;
> +	int i;
> +	FILE *file = fopen(filename, "r");
> +
> +	if (!file)
> +		return -1;
> +
> +	memset(linebuf, 0, UIO_MAX_NAME_SIZE);
> +	s = fgets(linebuf, UIO_MAX_NAME_SIZE, file);
> +	if (!s) {
> +		fclose(file);
> +		return -2;
> +	}
> +	for (i = 0; (*s) && (i < UIO_MAX_NAME_SIZE); i++) {
> +		if (*s == '\n')
> +			*s = '\0';
> +		s++;
> +	}
> +	fclose(file);
> +	return 0;
> +}
> +
> +static int uio_get_map_size(const int udev_id, uint64_t *map_size)
> +{
> +	int ret;
> +	char filename[64];
> +
> +	*map_size = UIO_INVALID_SIZE;
> +	snprintf(filename, sizeof(filename), "%s/uio%d/maps/map0/size",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file)
> +		return -1;
> +
> +	ret = fscanf(file, "0x%" PRIx64, map_size);
> +	fclose(file);
> +	if (ret < 0)
> +		return -2;
> +
> +	return 0;
> +}
> +
> +static int uio_get_map_addr(const int udev_id, uint64_t *map_addr)
> +{
> +	int ret;
> +	char filename[64];
> +
> +	*map_addr = UIO_INVALID_ADDR;
> +	snprintf(filename, sizeof(filename), "%s/uio%d/maps/map0/addr",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file)
> +		return -1;
> +
> +	ret = fscanf(file, "0x%" PRIx64, map_addr);
> +	fclose(file);
> +	if (ret < 0)
> +		return -2;
> +
> +	return 0;
> +}
> +
> +static int uio_get_map_name(const int udev_id, char *map_name)
> +{
> +	char filename[64];
> +
> +	snprintf(filename, sizeof(filename), "%s/uio%d/maps/map0/name",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	return line_buf_from_filename(filename, map_name);
> +}
> +
> +static int uio_get_info_name(const int udev_id, char *info_name)
> +{
> +	char filename[64];
> +
> +	snprintf(filename, sizeof(filename), "%s/uio%d/name",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	return line_buf_from_filename(filename, info_name);
> +}
> +
> +static int uio_get_info_version(const int udev_id, char *info_ver)
> +{
> +	char filename[64];
> +
> +	snprintf(filename, sizeof(filename), "%s/uio%d/version",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	return line_buf_from_filename(filename, info_ver);
> +}
> +
> +static int uio_get_info_event_count(const int udev_id, unsigned long *event_count)
> +{
> +	int ret;
> +	char filename[64];
> +
> +	*event_count = 0;
> +	snprintf(filename, sizeof(filename), "%s/uio%d/event",
> +			 UIO_DEV_DIR, udev_id);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file)
> +		return -1;
> +
> +	ret = fscanf(file, "%d", (int *)event_count);
> +	fclose(file);
> +	if (ret < 0)
> +		return -2;
> +
> +	return 0;
> +}
> +
> +static int uio_get_udev_id(const char *name, int *udev_id)
> +{
> +	struct dirent **namelist;
> +	int n, len;
> +	char filename[64];
> +	char buf[256];
> +
> +	n = scandir(UIO_DEV_DIR, &namelist, 0, alphasort);
> +	if (n <= 0) {
> +		MACB_LOG(ERR,
> +				 "scandir for %s "
> +				 "failed, errno = %d (%s)",
> +				 UIO_DEV_DIR, errno, strerror(errno));
> +		return 0;
> +	}
> +
> +	while (n--) {
> +		snprintf(filename, sizeof(filename), "%s/%s", UIO_DEV_DIR,
> +				 namelist[n]->d_name);
> +		len = readlink(filename, buf, sizeof(buf) - 1);
> +		if (len != -1)
> +			buf[len] = '\0';
> +		if (strstr(buf, name)) {
> +			*udev_id = udev_id_from_filename(namelist[n]->d_name);
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int uio_get_all_info(struct macb_iomem *iomem)
> +{
> +	struct uio_info *info = iomem->info;
> +	struct uio_map *map = &info->map;
> +	char *name = iomem->name;
> +
> +	if (!info)
> +		return -EINVAL;
> +
> +	uio_get_udev_id(name, &iomem->udev_id);
> +
> +	uio_get_info_name(iomem->udev_id, info->name);
> +	uio_get_info_version(iomem->udev_id, info->version);
> +	uio_get_info_event_count(iomem->udev_id, &info->event_count);
> +	uio_get_map_name(iomem->udev_id, map->name);
> +	uio_get_map_addr(iomem->udev_id, &map->addr);
> +	uio_get_map_size(iomem->udev_id, &map->size);
> +
> +	return 0;
> +}
> +
> +int macb_uio_exist(const char *name)
> +{
> +	struct dirent **namelist;
> +	int n, ret = 0;
> +
> +	n = scandir(MACB_UIO_DRV_DIR, &namelist,
> +				0, alphasort);
> +	if (n <= 0) {
> +		MACB_LOG(ERR,
> +				 "scandir for %s "
> +				 "failed, errno = %d (%s)",
> +				 MACB_UIO_DRV_DIR, errno, strerror(errno));
> +		return 0;
> +	}
> +
> +	while (n--) {
> +		if (!strncmp(namelist[n]->d_name, name, strlen(name)))
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +int macb_uio_init(const char *name, struct macb_iomem **iomem)
> +{
> +	struct macb_iomem *new;
> +	int ret;
> +
> +	new = malloc(sizeof(struct macb_iomem));
> +	if (!new) {
> +		MACB_LOG(ERR, "No memory for IOMEM obj.");
> +		return -ENOMEM;
> +	}
> +	memset(new, 0, sizeof(struct macb_iomem));
> +
> +	new->name = strdup(name);
> +	if (!new->name) {
> +		MACB_LOG(ERR, "No memory for IOMEM-name obj.");
> +		ret = -ENOMEM;
> +		goto out_free;
> +	}
> +
> +	new->info = malloc(sizeof(struct uio_info));
> +	if (!new->info) {
> +		ret = -ENOSPC;
> +		goto out_free_name;
> +	}
> +
> +	uio_get_all_info(new);
> +
> +	*iomem = new;
> +
> +	return 0;
> +
> +out_free_name:
> +	free(new->name);
> +out_free:
> +	free(new);
> +
> +	return ret;
> +}
> +
> +void macb_uio_deinit(struct macb_iomem *iomem)
> +{
> +	free(iomem->info);
> +	free(iomem->name);
> +	free(iomem);
> +}
> +
> +static void *uio_single_mmap(struct uio_info *info, int fd, phys_addr_t paddr)
> +{
> +	unsigned long pagesize;
> +	size_t offset;
> +
> +	if (!fd)
> +		return NULL;
> +
> +	if (info->map.size == UIO_INVALID_SIZE)
> +		return NULL;
> +
> +	pagesize = getpagesize();
> +	offset = paddr - (paddr & ~((unsigned long)pagesize - 1));
> +	info->map.internal_addr =
> +		mmap(NULL, info->map.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> +
> +	if (info->map.internal_addr != MAP_FAILED) {
> +		info->map.internal_addr = (void *)((unsigned long)info->map.internal_addr + offset);
> +		return info->map.internal_addr;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void uio_single_munmap(struct uio_info *info)
> +{
> +	munmap(info->map.internal_addr, info->map.size);
> +}
> +
> +int macb_uio_map(struct macb_iomem *iomem, phys_addr_t *pa, void **va, phys_addr_t paddr)
> +{
> +	if (iomem->fd <= 0) {
> +		char dev_name[16];
> +		snprintf(dev_name, sizeof(dev_name), "/dev/uio%d",
> +				 iomem->udev_id);
> +		iomem->fd = open(dev_name, O_RDWR);
> +	}
> +
> +	if (iomem->fd > 0) {
> +		*va = uio_single_mmap(iomem->info, iomem->fd, paddr);
> +		if (!*va)
> +			return -EINVAL;
> +
> +		if (pa)
> +			*pa = paddr;
> +	} else {
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int macb_uio_unmap(struct macb_iomem *iomem)
> +{
> +	uio_single_munmap(iomem->info);
> +	if (iomem->fd > 0)
> +		close(iomem->fd);
> +	return 0;
> +}
> diff --git a/drivers/net/macb/base/macb_uio.h b/drivers/net/macb/base/macb_uio.h
> new file mode 100644
> index 0000000..7fb8298
> --- /dev/null
> +++ b/drivers/net/macb/base/macb_uio.h
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +#include "macb_common.h"
> +
> +#ifndef _MACB_UIO_H_
> +#define _MACB_UIO_H_
> +
> +#define UIO_HDR_STR		"uio_%s"
> +#define UIO_HDR_SZ		sizeof(UIO_HDR_STR)
> +
> +#define UIO_MAX_NAME_SIZE	64
> +#define UIO_MAX_NUM		255
> +
> +#define UIO_INVALID_SIZE	0
> +#define UIO_INVALID_ADDR	(~0)
> +#define UIO_INVALID_FD		-1
> +
> +#define UIO_MMAP_NOT_DONE	0
> +#define UIO_MMAP_OK		1
> +#define UIO_MMAP_FAILED		2
> +
> +struct uio_map {
> +	uint64_t addr;
> +	uint64_t size;
> +	char name[UIO_MAX_NAME_SIZE];
> +	void *internal_addr;
> +};
> +
> +struct uio_info {
> +	struct uio_map map;
> +	unsigned long event_count;
> +	char name[UIO_MAX_NAME_SIZE];
> +	char version[UIO_MAX_NAME_SIZE];
> +};
> +
> +struct macb_iomem {
> +	char *name;
> +	int udev_id;
> +	int fd;
> +	struct uio_info *info;
> +};
> +
> +int macb_uio_exist(const char *name);
> +int macb_uio_init(const char *name, struct macb_iomem **iomem);
> +void macb_uio_deinit(struct macb_iomem *iomem);
> +int macb_uio_map(struct macb_iomem *iomem, phys_addr_t *pa, void **va, phys_addr_t paddr);
> +int macb_uio_unmap(struct macb_iomem *iomem);
> +
> +#endif /* _MACB_UIO_H_ */
> diff --git a/drivers/net/macb/base/meson.build b/drivers/net/macb/base/meson.build
> new file mode 100644
> index 0000000..888ac92
> --- /dev/null
> +++ b/drivers/net/macb/base/meson.build
> @@ -0,0 +1,25 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2022 Phytium Technology Co., Ltd.
> +
> +sources = [
> +        'macb_common.c',
> +        'macb_uio.c',
> +        'generic_phy.c',
> +]
> +
> +error_cflags = ['-Wno-unused-value',
> +        '-Wno-unused-but-set-variable',
> +        '-Wno-unused-variable',
> +        '-Wno-unused-parameter',
> +        ]
> +c_args = cflags
> +foreach flag: error_cflags
> +    if cc.has_argument(flag)
> +        c_args += flag
> +    endif
> +endforeach
> +
> +base_lib = static_library('macb_base', sources,
> +    dependencies: static_rte_eal,
> +    c_args: c_args)
> +base_objs = base_lib.extract_all_objects()
> diff --git a/drivers/net/macb/macb_ethdev.c b/drivers/net/macb/macb_ethdev.c
> new file mode 100644
> index 0000000..3302f35
> --- /dev/null
> +++ b/drivers/net/macb/macb_ethdev.c
> @@ -0,0 +1,1755 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022~2023 Phytium Technology Co., Ltd.
> + */
> +
> +#include <rte_bus_vdev.h>
> +#include <ethdev_driver.h>
> +#include <ethdev_vdev.h>
> +#include <rte_kvargs.h>
> +#include <rte_string_fns.h>
> +
> +#include "macb_rxtx.h"
> +
> +#define MACB_DRIVER_VERSION "5.8"
> +#define MACB_DEVICE_NAME_ARG "device"
> +#define MACB_USE_PHYDRV_ARG "usephydrv"
> +#define MACB_MAC_ADDRS_MAX 256
> +#define MAX_BUF_STR_LEN 256
> +#define MACB_PDEV_PATH "/sys/bus/platform/devices"
> +#define MACB_LINK_UPDATE_CHECK_TIMEOUT 90	/* 9s */
> +#define MACB_LINK_UPDATE_CHECK_INTERVAL 100 /* ms */
> +
> +#define MACB_DEFAULT_TX_FREE_THRESH 32
> +#define MACB_DEFAULT_TX_RSBIT_THRESH 16
> +
> +#define MACB_DEFAULT_RX_FREE_THRESH 16
> +
> +int macb_logtype;
> +static int macb_log_initialized;
> +
> +static const char *const valid_args[] = {
> +	MACB_DEVICE_NAME_ARG,
> +	MACB_USE_PHYDRV_ARG,
> +	NULL};
> +
> +struct macb_devices {
> +	const char *names[MACB_MAX_PORT_NUM];
> +	uint32_t idx;
> +};
> +
> +static int macb_dev_num;
> +
> +static int macb_phy_auto_detect(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	uint16_t phyad;
> +	uint32_t phyid, phyid1, phyid2;
> +	struct phy_device *phydev = bp->phydev;
> +	struct phy_driver **phydrv;
> +
> +	/*
> +	 * Custom external phy driver need to be added to phydrv_list.
> +	 */
> +	struct phy_driver *phydrv_list[] = {
> +		&genphy_driver,
> +		NULL
> +	};
> +
> +	/*internal phy */
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII) {
> +		phydev->drv = &macb_usxgmii_pcs_driver;
> +		return 0;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
> +		(bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link)) {
> +		phydev->drv = &macb_gbe_pcs_driver;
> +		return 0;
> +	}
> +
> +	/*external phy use no driver*/
> +	if (!bp->phydrv_used) {
> +		phydev->drv = NULL;
> +		return 0;
> +	}
> +
> +	for (phyad = 0; phyad < MAX_PHY_AD_NUM; phyad++) {
> +		phyid2 = macb_mdio_read(bp, phyad, GENERIC_PHY_PHYSID2);
> +		phyid1 = macb_mdio_read(bp, phyad, GENERIC_PHY_PHYSID1);
> +		phyid = phyid2 | (phyid1 << PHY_ID_OFFSET);
> +		/* If the phy_id is mostly Fs, there is no device there */
> +		if (phyid && ((phyid & 0x1fffffff) != 0x1fffffff)) {
> +			phydev->phy_id = phyid;
> +			phydev->phyad = phyad;
> +			break;
> +		}
> +	}
> +
> +	/* check if already registered */
> +	for (phydrv = phydrv_list; *phydrv; phydrv++) {
> +		if ((phydev->phy_id & (*phydrv)->phy_id_mask) == (*phydrv)->phy_id)
> +			break;
> +	}
> +
> +	if (*phydrv != NULL) {
> +		phydev->drv = *phydrv;
> +		MACB_INFO("Phy driver %s used", phydev->drv->name);
> +	} else {
> +		phydev->drv = &genphy_driver;
> +		MACB_INFO("Unknown phyid: 0x%x, general phy driver used", phyid);
> +	}
> +
> +	/* phy probe */
> +	if (phydev->drv && phydev->drv->probe)
> +		phydev->drv->probe(phydev);
> +
> +	return 0;
> +}
> +
> +/**
> + * DPDK callback to enable promiscuous mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return 0
> + *
> + *
> + */
> +static int eth_macb_promiscuous_enable(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	uint32_t cfg;
> +
> +	if (!bp) {
> +		MACB_LOG(DEBUG, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	cfg = macb_readl(bp, NCFGR);
> +	cfg |= MACB_BIT(CAF);
> +
> +	macb_writel(bp, NCFGR, cfg);
> +
> +	return 0;
> +}
> +
> +/**
> + * DPDK callback to disable promiscuous mode.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return 0
> + *
> + *
> + */
> +static int eth_macb_promiscuous_disable(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	uint32_t cfg;
> +
> +	if (!bp) {
> +		MACB_LOG(DEBUG, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	cfg = macb_readl(bp, NCFGR);
> +	cfg &= ~MACB_BIT(CAF);
> +
> +	macb_writel(bp, NCFGR, cfg);
> +
> +	return 0;
> +}
> +
> +static int eth_macb_allmulticast_enable(struct rte_eth_dev *dev)
> +{
> +	unsigned long cfg;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +
> +	cfg = macb_readl(bp, NCFGR);
> +	/* Enable all multicast mode */
> +	macb_or_gem_writel(bp, HRB, -1);
> +	macb_or_gem_writel(bp, HRT, -1);
> +	cfg |= MACB_BIT(NCFGR_MTI);
> +
> +	macb_writel(bp, NCFGR, cfg);
> +	return 0;
> +}
> +
> +static int eth_macb_allmulticast_disable(struct rte_eth_dev *dev)
> +{
> +	unsigned long cfg;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +
> +	if (dev->data->promiscuous == 1)
> +		return 0; /* must remain in all_multicast mode */
> +
> +	cfg = macb_readl(bp, NCFGR);
> +	/* Disable all multicast mode */
> +	macb_or_gem_writel(bp, HRB, 0);
> +	macb_or_gem_writel(bp, HRT, 0);
> +	cfg &= ~MACB_BIT(NCFGR_MTI);
> +
> +	macb_writel(bp, NCFGR, cfg);
> +	return 0;
> +}
> +
> +static int eth_macb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	struct phy_device *phydev = bp->phydev;
> +	struct rte_eth_link link;
> +	int count, link_check;
> +
> +	if (!priv->bp) {
> +		MACB_LOG(ERR, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	for (count = 0; count < MACB_LINK_UPDATE_CHECK_TIMEOUT; count++) {
> +		macb_check_for_link(bp);
> +		link_check = bp->link;
> +		if (link_check || wait_to_complete == 0)
> +			break;
> +		rte_delay_ms(MACB_LINK_UPDATE_CHECK_INTERVAL);
> +	}
> +	memset(&link, 0, sizeof(link));
> +
> +	if (link_check) {
> +		if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII ||
> +			bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX ||
> +			bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
> +			bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
> +			(bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link) ||
> +			!bp->phydrv_used) {
> +			link.link_speed = bp->speed;
> +			link.link_duplex =
> +				bp->duplex ? RTE_ETH_LINK_FULL_DUPLEX : RTE_ETH_LINK_HALF_DUPLEX;
> +		} else {
> +			/* get phy link info */
> +			if (phydev->drv && phydev->drv->read_status)
> +				phydev->drv->read_status(phydev);
> +
> +			link.link_speed = phydev->speed;
> +			link.link_duplex = phydev->duplex ? RTE_ETH_LINK_FULL_DUPLEX :
> +					   RTE_ETH_LINK_HALF_DUPLEX;
> +		}
> +		link.link_status = RTE_ETH_LINK_UP;
> +		link.link_autoneg =
> +			!(dev->data->dev_conf.link_speeds & RTE_ETH_LINK_SPEED_FIXED);
> +	} else if (!link_check) {
> +		link.link_speed = RTE_ETH_SPEED_NUM_NONE;
> +		link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
> +		link.link_status = RTE_ETH_LINK_DOWN;
> +		link.link_autoneg = RTE_ETH_LINK_FIXED;
> +	}
> +
> +	return rte_eth_linkstatus_set(dev, &link);
> +}
> +
> +static void macb_interrupt_handler(void *param)
> +{
> +	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct rte_eth_link link;
> +	char status[128];
> +
> +	if (priv->stopped)
> +		return;
> +
> +	if (eth_macb_link_update(dev, 0) < 0)
> +		return;
> +
> +	rte_eth_linkstatus_get(dev, &link);
> +	rte_eth_link_to_str(status, sizeof(status), &link);
> +	MACB_INFO("Port %u: %s", dev->data->port_id, status);
> +
> +	macb_link_change(priv->bp);
> +	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
> +}
> +
> +static int eth_macb_dev_set_link_up(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	struct phy_device *phydev = bp->phydev;
> +
> +	if (!bp) {
> +		MACB_LOG(ERR, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	/* phy link up */
> +	if (phydev->drv && phydev->drv->resume)
> +		phydev->drv->resume(phydev);
> +
> +	return 0;
> +}
> +
> +static int eth_macb_dev_set_link_down(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	struct phy_device *phydev = bp->phydev;
> +
> +	if (!bp) {
> +		MACB_LOG(ERR, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	/* phy link down */
> +	if (phydev->drv && phydev->drv->suspend)
> +		phydev->drv->suspend(phydev);
> +
> +	return 0;
> +}
> +
> +/**
> + * DPDK callback to get device statistics.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param stats
> + *   Stats structure output buffer.
> + *
> + * @return
> + *   0 on success, negative error value otherwise.
> + */
> +static int eth_macb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct gem_stats *hwstat = &priv->bp->hw_stats.gem;
> +
> +	RTE_ASSERT(priv->bp != NULL);
> +
> +	macb_get_stats(priv->bp);
> +
> +	stats->ipackets = hwstat->rx_frames - priv->prev_stats.ipackets;
> +	stats->opackets = hwstat->tx_frames - priv->prev_stats.opackets;
> +	stats->ibytes = hwstat->rx_octets_31_0 + (hwstat->rx_octets_47_32 << 32) -
> +					priv->prev_stats.ibytes;
> +	stats->obytes = hwstat->tx_octets_31_0 + (hwstat->tx_octets_47_32 << 32) -
> +					priv->prev_stats.obytes;
> +	stats->imissed = hwstat->rx_resource_drops + hwstat->rx_overruns -
> +					priv->prev_stats.imissed;
> +	stats->ierrors =
> +		(hwstat->rx_frame_check_sequence_errors + hwstat->rx_alignment_errors +
> +		 hwstat->rx_oversize_frames + hwstat->rx_jabbers +
> +		 hwstat->rx_undersized_frames + hwstat->rx_length_field_frame_errors +
> +		 hwstat->rx_ip_header_checksum_errors + hwstat->rx_tcp_checksum_errors +
> +		 hwstat->rx_udp_checksum_errors) -
> +		priv->prev_stats.ierrors;
> +	stats->oerrors =
> +		(hwstat->tx_late_collisions + hwstat->tx_excessive_collisions +
> +		 hwstat->tx_underrun + hwstat->tx_carrier_sense_errors) -
> +		priv->prev_stats.oerrors;
> +
> +	return 0;
> +}
> +
> +static int eth_macb_stats_reset(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	int ret;
> +
> +	if (!priv->bp) {
> +		MACB_LOG(ERR, "Failed to get private data!");
> +		return -EPERM;
> +	}
> +
> +	memset(&priv->prev_stats, 0, sizeof(struct rte_eth_stats));
> +	ret = eth_macb_stats_get(dev, &priv->prev_stats);
> +	if (unlikely(ret)) {
> +		MACB_LOG(ERR, "Failed to reset port statistics.");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int eth_macb_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
> +								  struct rte_eth_dev_info *dev_info)
> +{
> +	dev_info->max_mac_addrs = 1;
> +	dev_info->max_rx_queues = MACB_MAX_QUEUES;
> +	dev_info->max_tx_queues = MACB_MAX_QUEUES;
> +	dev_info->max_rx_pktlen = MAX_JUMBO_FRAME_SIZE;
> +
> +	/* MAX JUMBO FRAME */
> +	dev_info->max_rx_pktlen = MACB_MAX_JUMBO_FRAME;
> +
> +	dev_info->max_mtu = dev_info->max_rx_pktlen - MACB_ETH_OVERHEAD;
> +	dev_info->min_mtu = RTE_ETHER_MIN_MTU;
> +
> +	dev_info->speed_capa = RTE_ETH_LINK_SPEED_10M | RTE_ETH_LINK_SPEED_100M |
> +						   RTE_ETH_LINK_SPEED_1G | RTE_ETH_LINK_SPEED_10G;
> +
> +	dev_info->rx_queue_offload_capa = macb_get_rx_queue_offloads_capa(dev);
> +	dev_info->rx_offload_capa =
> +		macb_get_rx_port_offloads_capa(dev) | dev_info->rx_queue_offload_capa;
> +	dev_info->tx_queue_offload_capa = RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
> +					RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM;

I don't see any handling of 'ol_flags' in 'xmit_pkts'. Is this always enabled?

I don't see handling of 'tx_conf->offloads' anywhere in the code. If the driver
advertises these offloads in 'tx_queue_offload_capa', then it agrees those can
be enabled/disabled on per-queue bases. Consider to check this for consistency.

> +	dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
> +				RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
> +	dev_info->default_rxconf = (struct rte_eth_rxconf) {
> +		.rx_free_thresh = MACB_DEFAULT_RX_FREE_THRESH,
> +		.offloads = 0,
> +	};
> +
> +	dev_info->default_txconf = (struct rte_eth_txconf) {
> +		.tx_free_thresh = MACB_DEFAULT_TX_FREE_THRESH,
> +		.tx_rs_thresh = MACB_DEFAULT_TX_RSBIT_THRESH,
> +		.offloads = 0,
> +	};
> +
> +	dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
> +		.nb_max = MACB_MAX_RING_DESC,
> +		.nb_min = MACB_MIN_RING_DESC,
> +		.nb_align = MACB_RXD_ALIGN,
> +	};
> +
> +	dev_info->tx_desc_lim = (struct rte_eth_desc_lim) {
> +		.nb_max = MACB_MAX_RING_DESC,
> +		.nb_min = MACB_MIN_RING_DESC,
> +		.nb_align = MACB_TXD_ALIGN,
> +	};
> +
> +	dev_info->max_rx_queues = MACB_MAX_QUEUES;
> +	dev_info->max_tx_queues = MACB_MAX_QUEUES;
> +
> +
> +	return 0;
> +}
> +
> +static const uint32_t *
> +eth_macb_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused,
> +				  size_t *num_ptypes __rte_unused)
> +{
> +	static const uint32_t ptypes[] = {RTE_PTYPE_L3_IPV4, RTE_PTYPE_L3_IPV6,
> +					  RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP};
> +
> +	return ptypes;
> +}
> +
> +/**
> + * DPDK callback to set mtu.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + * @param mtu
> + *   The value of Maximum Transmission Unit (MTU) to set
> + */
> +static int eth_macb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
> +{
> +	u32 frame_size = mtu + MACB_ETH_OVERHEAD;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	u32 config;
> +
> +	config = macb_readl(bp, NCFGR);
> +
> +	/* refuse mtu that requires the support of scattered packets when this
> +	 * feature has not been enabled before.
> +	 */
> +	if (!dev->data->scattered_rx &&
> +		frame_size > dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM) {
> +		MACB_LOG(ERR, "mtu setting rejected.");
> +		return -EINVAL;
> +	}
> +
> +	/* switch to jumbo mode if needed */
> +	if (mtu > RTE_ETHER_MAX_LEN)
> +		config |= MACB_BIT(JFRAME);
> +	else
> +		config &= ~MACB_BIT(JFRAME);
> +	macb_writel(bp, NCFGR, config);
> +	gem_writel(bp, JML, frame_size);
> +
> +	return 0;
> +}
> +
> +/* macb_set_hwaddr
> + * set mac address.
> + *
> + * This function complete mac addr set.
> + *
> + * @param dev
> + *   A pointer to the macb.
> + *
> + * @modify author
> + *   Mengxiangbo
> + * @modify time
> + *   2021-02-07
> + * @modify reason
> + *   build
> + **/
> +static void eth_macb_set_hwaddr(struct macb *bp)
> +{
> +	u32 bottom;
> +	u16 top;
> +
> +	bottom = cpu_to_le32(*((u32 *)bp->dev->data->mac_addrs->addr_bytes));
> +	macb_or_gem_writel(bp, SA1B, bottom);
> +	top = cpu_to_le16(*((u16 *)(bp->dev->data->mac_addrs->addr_bytes + 4)));
> +	macb_or_gem_writel(bp, SA1T, top);
> +
> +	/* Clear unused address register sets */
> +	macb_or_gem_writel(bp, SA2B, 0);
> +	macb_or_gem_writel(bp, SA2T, 0);
> +	macb_or_gem_writel(bp, SA3B, 0);
> +	macb_or_gem_writel(bp, SA3T, 0);
> +	macb_or_gem_writel(bp, SA4B, 0);
> +	macb_or_gem_writel(bp, SA4T, 0);
> +}
> +
> +static void macb_get_hwaddr(struct macb *bp)
> +{
> +	struct rte_ether_addr mac_addr;
> +	u32 bottom;
> +	u16 top;
> +	u8 addr[6];
> +
> +	bottom = macb_or_gem_readl(bp, SA1B);
> +	top = macb_or_gem_readl(bp, SA1T);
> +
> +	addr[0] = bottom & 0xff;
> +	addr[1] = (bottom >> 8) & 0xff;
> +	addr[2] = (bottom >> 16) & 0xff;
> +	addr[3] = (bottom >> 24) & 0xff;
> +	addr[4] = top & 0xff;
> +	addr[5] = (top >> 8) & 0xff;
> +
> +	memcpy(mac_addr.addr_bytes, addr, RTE_ETHER_ADDR_LEN);
> +	if (!rte_is_valid_assigned_ether_addr(&mac_addr)) {
> +		MACB_LOG(INFO, "Invalid MAC address, using random.");
> +		rte_eth_random_addr(addr);
> +	}
> +	memcpy(bp->dev->data->mac_addrs->addr_bytes, addr, sizeof(addr));
> +}
> +
> +const struct macb_config macb_gem1p0_mac_config = {
> +	.caps = MACB_CAPS_MACB_IS_GEM | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
> +			MACB_CAPS_JUMBO | MACB_CAPS_BD_RD_PREFETCH |
> +			MACB_CAPS_ISR_CLEAR_ON_WRITE | MACB_CAPS_PERFORMANCE_OPTIMIZING |
> +			MACB_CAPS_SEL_CLK_HW,
> +	.dma_burst_length = 16,
> +	.jumbo_max_len = 10240,
> +	.sel_clk_hw = macb_gem1p0_sel_clk,
> +};
> +
> +static const struct macb_config macb_gem2p0_mac_config = {
> +	.caps = MACB_CAPS_MACB_IS_GEM | MACB_CAPS_GIGABIT_MODE_AVAILABLE |
> +				MACB_CAPS_JUMBO | MACB_CAPS_BD_RD_PREFETCH |
> +				MACB_CAPS_ISR_CLEAR_ON_WRITE | MACB_CAPS_PERFORMANCE_OPTIMIZING |
> +				MACB_CAPS_SEL_CLK_HW,
> +	.dma_burst_length = 16,
> +	.jumbo_max_len = 10240,
> +	.sel_clk_hw = macb_gem2p0_sel_clk,
> +};
> +
> +static int eth_macb_set_default_mac_addr(struct rte_eth_dev *dev,
> +				     struct rte_ether_addr *mac_addr)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +
> +	memcpy(bp->dev->data->mac_addrs, mac_addr, RTE_ETHER_ADDR_LEN);
> +
> +	eth_macb_set_hwaddr(bp);
> +
> +	return 0;
> +}
> +
> +/* macb_dev_configure
> + * Macb dev init and hw init   include some register init and some
> + * Nic operation func appoint .
> + *
> + * This function complete hw initialization.
> + *
> + * @param dev
> + *   A pointer to the dev.
> + *
> + **/
> +static int eth_macb_dev_configure(struct rte_eth_dev *dev)
> +{
> +	u32 reg, val = 0;
> +	bool native_io;
> +	unsigned int queue_mask, num_queues;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	const struct macb_config *macb_config = NULL;
> +
> +	bp->dev_type = priv->dev_type;
> +	if (bp->dev_type == DEV_TYPE_PHYTIUM_GEM1P0_MAC) {
> +		macb_config = &macb_gem1p0_mac_config;
> +	} else if (bp->dev_type == DEV_TYPE_PHYTIUM_GEM2P0_MAC) {
> +		macb_config = &macb_gem2p0_mac_config;
> +	} else {
> +		MACB_LOG(ERR, "unsupportted device.");
> +		return -ENODEV;
> +	}
> +
> +	native_io = macb_hw_is_native_io(bp);
> +	macb_probe_queues(bp->base, native_io, &queue_mask, &num_queues);
> +
> +	bp->native_io = native_io;
> +	bp->num_queues = num_queues;
> +	bp->tx_ring_size = MACB_TX_RING_SIZE;
> +	bp->rx_ring_size = MACB_RX_RING_SIZE;
> +	bp->queue_mask = queue_mask;
> +
> +	if (macb_config) {
> +		bp->dma_burst_length = macb_config->dma_burst_length;
> +		bp->jumbo_max_len = macb_config->jumbo_max_len;
> +		bp->sel_clk_hw = macb_config->sel_clk_hw;
> +	}
> +
> +	/* setup capabilities */
> +	macb_configure_caps(bp, macb_config);
> +	bp->hw_dma_cap = HW_DMA_CAP_64B;
> +
> +	/* set MTU */
> +	dev->data->mtu = RTE_ETHER_MTU;
> +
> +	/* enable lsc interrupt */
> +	dev->data->dev_conf.intr_conf.lsc = true;
> +
> +	/* prefetch init */
> +	if (bp->caps & MACB_CAPS_BD_RD_PREFETCH) {
> +		val = GEM_BFEXT(RXBD_RDBUFF, gem_readl(bp, DCFG10));
> +		if (val)
> +			bp->rx_bd_rd_prefetch =
> +				(4 << (val - 1)) * macb_dma_desc_get_size(bp);
> +
> +		val = GEM_BFEXT(TXBD_RDBUFF, gem_readl(bp, DCFG10));
> +		if (val)
> +			bp->tx_bd_rd_prefetch =
> +				(4 << (val - 1)) * macb_dma_desc_get_size(bp);
> +	}
> +
> +	/* Enable management port */
> +	macb_writel(bp, NCR, MACB_BIT(MPE));
> +
> +	/* get mac address */
> +	macb_get_hwaddr(bp);
> +
> +	/* Checksum offload is only available on gem with packet buffer */
> +	if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE))
> +		dev->data->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
> +	/* Scatter gather disable */
> +	if (bp->caps & MACB_CAPS_SG_DISABLED)
> +		dev->data->dev_conf.rxmode.offloads &= ~RTE_ETH_RX_OFFLOAD_SCATTER;
> +
> +	/* Check RX Flow Filters support.
> +	 * Max Rx flows set by availability of screeners & compare regs:
> +	 * each 4-tuple define requires 1 T2 screener reg + 3 compare regs
> +	 */
> +	reg = gem_readl(bp, DCFG8);
> +	bp->max_tuples = min((GEM_BFEXT(SCR2CMP, reg) / 3), GEM_BFEXT(T2SCR, reg));
> +	if (bp->max_tuples > 0) {
> +		if (GEM_BFEXT(SCR2ETH, reg) > 0) {
> +			reg = 0;
> +			reg = GEM_BFINS(ETHTCMP, (uint16_t)ETH_P_IP, reg);
> +			gem_writel_n(bp, ETHT, SCRT2_ETHT, reg);
> +			priv->hw_features |= RTE_5TUPLE_FLAGS;
> +		} else {
> +			bp->max_tuples = 0;
> +		}
> +	}
> +	/*
> +	 * Initialize to TRUE. If any of Rx queues doesn't meet the bulk
> +	 * allocation or vector Rx preconditions we will reset it.
> +	 */
> +	bp->rx_bulk_alloc_allowed = true;
> +	bp->rx_vec_allowed = true;
> +
> +	return 0;
> +}
> +
> +static u32 macb_mdc_clk_div(struct macb *bp)
> +{
> +	u32 config;
> +	unsigned long pclk_hz;
> +	struct macb_priv *priv = bp->dev->data->dev_private;
> +
> +	pclk_hz = priv->pclk_hz;
> +	if (pclk_hz <= 20000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV8);
> +	else if (pclk_hz <= 40000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV16);
> +	else if (pclk_hz <= 80000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV32);
> +	else if (pclk_hz <= 120000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV48);
> +	else if (pclk_hz <= 160000000)
> +		config = GEM_BF(CLK, GEM_CLK_DIV64);
> +	else
> +		config = GEM_BF(CLK, GEM_CLK_DIV96);
> +
> +	return config;
> +}
> +
> +static void macb_configure_dma(struct macb *bp)
> +{
> +	struct macb_rx_queue *rxq;
> +	u32 buffer_size;
> +	unsigned int i;
> +	u32 dmacfg;
> +
> +	/* Dma rx  buffer size set */
> +	buffer_size = bp->rx_buffer_size / RX_BUFFER_MULTIPLE;
> +	if (macb_is_gem(bp)) {
> +		dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
> +		for (i = 0; i < bp->dev->data->nb_rx_queues; i++) {
> +			rxq = bp->dev->data->rx_queues[i];
> +			if (i != 0)
> +				queue_writel(rxq, RBQS, buffer_size);
> +			else
> +				dmacfg |= GEM_BF(RXBS, buffer_size);
> +		}
> +
> +		/* Disable PTP */
> +		dmacfg &= ~GEM_BIT(RXEXT);
> +		dmacfg &= ~GEM_BIT(TXEXT);
> +
> +		/* Fixed burst length for DMA set */
> +		if (bp->dma_burst_length)
> +			dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg);
> +
> +		/* TX RX packet buffer memory size select */
> +		dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
> +		dmacfg &= ~GEM_BIT(ENDIA_PKT);
> +
> +		/* Big little endian set */
> +		if (bp->native_io)
> +			dmacfg &= ~GEM_BIT(ENDIA_DESC);
> +		else
> +			dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
> +
> +		/* Dma addr bit width set */
> +		dmacfg &= ~GEM_BIT(ADDR64);
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			dmacfg |= GEM_BIT(ADDR64);
> +
> +		/* TX IP/TCP/UDP checksum gen offload set */
> +		if (bp->dev->data->dev_conf.txmode.offloads & (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
> +		    RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM))
> +			dmacfg |= GEM_BIT(TXCOEN);
> +		else
> +			dmacfg &= ~GEM_BIT(TXCOEN);
> +
> +		gem_writel(bp, DMACFG, dmacfg);
> +	}
> +}
> +
> +static void macb_init_hw(struct macb *bp)
> +{
> +	u32 config;
> +	u32 max_len;
> +
> +	/* Config NCFGR register*/
> +	config = macb_mdc_clk_div(bp);
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII)
> +		config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
> +	config |= MACB_BF(RBOF, MACB_RX_DATA_OFFSET);
> +	config |= MACB_BIT(PAE);
> +	if (bp->dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC)
> +		config &= ~MACB_BIT(DRFCS);
> +	else
> +		config |= MACB_BIT(DRFCS);
> +
> +	/* Enable jumbo frames */
> +	if (bp->dev->data->mtu > RTE_ETHER_MTU)
> +		config |= MACB_BIT(JFRAME);
> +	else
> +		/* Receive oversized frames */
> +		config |= MACB_BIT(BIG);
> +
> +	/* Copy All Frames */
> +	if (bp->dev->data->promiscuous == 1)
> +		config |= MACB_BIT(CAF);
> +	else if (macb_is_gem(bp) && (bp->dev->data->dev_conf.rxmode.offloads &
> +								 RTE_ETH_RX_OFFLOAD_CHECKSUM))
> +		config |= GEM_BIT(RXCOEN);
> +
> +	config |= macb_dbw(bp);
> +
> +	/* RX IP/TCP/UDP checksum gen offload set */
> +	if (macb_is_gem(bp) &&
> +		(bp->dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM))
> +		config |= GEM_BIT(RXCOEN);
> +	macb_writel(bp, NCFGR, config);
> +
> +	if ((bp->caps & MACB_CAPS_SEL_CLK_HW) && bp->sel_clk_hw)
> +		bp->sel_clk_hw(bp);
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
> +		bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
> +		(bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link)) {
> +		macb_mac_with_pcs_config(bp);
> +	}
> +
> +	/* JUMBO value set */
> +	if (bp->dev->data->mtu > RTE_ETHER_MTU) {
> +		max_len = bp->dev->data->mtu + MACB_ETH_OVERHEAD;
> +		gem_writel(bp, JML, max_len);
> +	}
> +	bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
> +
> +	/* Set axi_pipe */
> +	if (bp->caps & MACB_CAPS_PERFORMANCE_OPTIMIZING)
> +		gem_writel(bp, AXI_PIPE, 0x1010);
> +}
> +
> +
> +static inline void macb_enable_rxtx(struct macb *bp)
> +{
> +	u32 ctrl = macb_readl(bp, NCR);
> +	ctrl |= MACB_BIT(RE) | MACB_BIT(TE);
> +	macb_writel(bp, NCR, ctrl);
> +}
> +
> +/* macb_dev_start
> + * start dev Complete hardware initialization .
> + *
> + * This function complete hw initialization.
> + *
> + * @param dev
> + *   A pointer to the dev.
> + *
> + **/
> +static int eth_macb_dev_start(struct rte_eth_dev *dev)
> +{
> +	int err;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	struct phy_device *phydev = bp->phydev;
> +	uint32_t *speeds;
> +	int num_speeds;
> +	bool setup_link = true;
> +
> +	/* Make sure the phy device is disabled */
> +	eth_macb_dev_set_link_down(dev);
> +
> +	/* phydev soft reset */
> +	if (phydev->drv && phydev->drv->soft_reset)
> +		phydev->drv->soft_reset(phydev);
> +
> +	if (phydev->drv && phydev->drv->config_init)
> +		phydev->drv->config_init(phydev);
> +
> +	/* hw reset */
> +	macb_reset_hw(bp);
> +
> +	/* set mac addr */
> +	eth_macb_set_hwaddr(bp);
> +
> +	/* hw init */
> +	macb_init_hw(bp);
> +
> +	/* tx queue phyaddr check */
> +	err = macb_tx_phyaddr_check(dev);
> +	if (err) {
> +		MACB_LOG(ERR, "Tx phyaddr check failed.");
> +		goto out;
> +	}
> +
> +	/* Init tx queue include mbuf mem alloc */
Odd. Which mbufs are allocated on Tx queue init?

> +	macb_eth_tx_init(dev);
> +
> +	/* rx queue phyaddr check */
> +	err = macb_rx_phyaddr_check(dev);
> +	if (err) {
> +		MACB_LOG(ERR, "Rx phyaddr check failed.");
> +		goto out;
> +	}
> +
> +	/* Init rx queue include mbuf mem alloc */
> +	err = macb_eth_rx_init(dev);
> +	if (err) {
> +		MACB_LOG(ERR, "Rx init failed.");
> +		goto out;
> +	}
> +
> +	macb_configure_dma(bp);
> +
> +	/* Enable receive and transmit. */
> +	macb_enable_rxtx(bp);
> +
> +	/* Make interface link up */
> +	err = eth_macb_dev_set_link_up(dev);
> +	if (err) {
> +		MACB_LOG(ERR, "Failed to set link up");
> +		goto out;
> +	}
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII ||
> +	    bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX ||
> +	    bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
> +	    bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
> +	    (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link))
> +		setup_link = false;
> +
> +	/* Setup link speed and duplex */
> +	if (setup_link) {
> +		speeds = &dev->data->dev_conf.link_speeds;
> +		if (*speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
> +			bp->autoneg = RTE_ETH_LINK_AUTONEG;
> +		} else {
> +			num_speeds = 0;
> +			bp->autoneg = RTE_ETH_LINK_FIXED;
> +
> +			if (*speeds &
> +			    ~(RTE_ETH_LINK_SPEED_10M_HD | RTE_ETH_LINK_SPEED_10M |
> +			    RTE_ETH_LINK_SPEED_100M_HD | RTE_ETH_LINK_SPEED_100M |
> +			    RTE_ETH_LINK_SPEED_1G | RTE_ETH_LINK_SPEED_FIXED |
> +			    RTE_ETH_LINK_SPEED_2_5G)) {
> +				num_speeds = -1;
> +				goto error_invalid_config;
> +			}
> +			if (*speeds & RTE_ETH_LINK_SPEED_10M_HD) {
> +				bp->speed = RTE_ETH_SPEED_NUM_10M;
> +				bp->duplex = RTE_ETH_LINK_HALF_DUPLEX;
> +				num_speeds++;
> +			} else if (*speeds & RTE_ETH_LINK_SPEED_10M) {
> +				bp->speed = RTE_ETH_SPEED_NUM_10M;
> +				bp->duplex = RTE_ETH_LINK_FULL_DUPLEX;
> +				num_speeds++;
> +			} else if (*speeds & RTE_ETH_LINK_SPEED_100M_HD) {
> +				bp->speed = RTE_ETH_SPEED_NUM_100M;
> +				bp->duplex = RTE_ETH_LINK_HALF_DUPLEX;
> +				num_speeds++;
> +			} else if (*speeds & RTE_ETH_LINK_SPEED_100M) {
> +				bp->speed = RTE_ETH_SPEED_NUM_100M;
> +				bp->duplex = RTE_ETH_LINK_FULL_DUPLEX;
> +				num_speeds++;
> +			} else if (*speeds & RTE_ETH_LINK_SPEED_1G) {
> +				bp->speed = RTE_ETH_SPEED_NUM_1G;
> +				bp->duplex = RTE_ETH_LINK_FULL_DUPLEX;
> +				num_speeds++;
> +			} else if (*speeds & RTE_ETH_LINK_SPEED_2_5G) {
> +				bp->speed = RTE_ETH_SPEED_NUM_2_5G;
> +				bp->duplex = RTE_ETH_LINK_FULL_DUPLEX;
> +				num_speeds++;
> +			}
> +			if (num_speeds == 0) {
> +				err = -EINVAL;
> +				goto error_invalid_config;
> +			}
> +		}
> +		macb_setup_link(bp);
> +	}
> +
> +	eth_macb_stats_reset(dev);
> +	if (!bp->phydrv_used)
> +		bp->link = true;
> +
> +	priv->stopped = false;
> +	return 0;
> +error_invalid_config:
> +	MACB_LOG(ERR, "Invalid advertised speeds (%u) for port %u",
> +			 dev->data->dev_conf.link_speeds, dev->data->port_id);
> +out:
> +	MACB_LOG(ERR, "Failed to start device");
> +	return err;
> +}
> +
> +static int eth_macb_dev_stop(struct rte_eth_dev *dev)
> +{
> +	u32 i;
> +	struct rte_eth_link link;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +
> +	if (priv->stopped)
> +		return 0;
> +
> +	/* link down the interface */
> +	eth_macb_dev_set_link_down(dev);
> +
> +	/* reset hw reg */
> +	macb_reset_hw(bp);
> +
> +	/* release rx queue mbuf free mem */
> +	for (i = 0; i < dev->data->nb_rx_queues; i++) {
> +		struct macb_rx_queue *rx_queue;
> +		if (!dev->data->rx_queues[i])
> +			continue;
> +		rx_queue = dev->data->rx_queues[i];
> +		macb_rx_queue_release_mbufs(rx_queue);
> +		macb_reset_rx_queue(rx_queue);
> +	}
> +
> +	/* release tx queue mbuf free mem */
> +	for (i = 0; i < dev->data->nb_tx_queues; i++) {
> +		struct macb_tx_queue *tx_queue;
> +		if (!dev->data->tx_queues[i])
> +			continue;
> +		tx_queue = dev->data->tx_queues[i];
> +		macb_tx_queue_release_mbufs(tx_queue);
> +		macb_reset_tx_queue(tx_queue, dev);
> +	}
> +
> +	/* clear the recorded link status */
> +	memset(&link, 0, sizeof(link));
> +	rte_eth_linkstatus_set(dev, &link);
> +
> +	if (!bp->phydrv_used)
> +		bp->link = false;
> +	dev->data->dev_started = 0;
> +	priv->stopped = true;
> +	return 0;
> +}
> +
> +/**
> + * DPDK callback to close the device.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + */
> +static int eth_macb_dev_close(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	int ret = 0, loop = 10;
> +
> +	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> +		return 0;
> +
> +	ret = eth_macb_dev_stop(dev);
> +
> +	do {
> +		loop--;
> +		int err;
> +		err = rte_intr_callback_unregister(priv->intr_handle,
> +						   macb_interrupt_handler, dev);
> +		if (err > 0)
> +			break;
> +		if (err != -EAGAIN || !loop) {
> +			MACB_LOG(WARNING, "Failed to unregister lsc callback.");
> +			break;
> +		}
> +		rte_delay_ms(10);
> +	} while (true);
> +
> +	macb_dev_free_queues(dev);
> +
> +	/* Ensure that register operations are completed before unmap. */
> +	rte_delay_ms(100);
> +	macb_iomem_deinit(priv->bp);
> +	rte_free(priv->bp->phydev);
> +	rte_free(priv->bp);
> +
> +	macb_dev_num--;
> +
> +	return ret;
> +}
> +
> +static const struct eth_dev_ops macb_ops = {
> +	.dev_set_link_up = eth_macb_dev_set_link_up,
> +	.dev_set_link_down = eth_macb_dev_set_link_down,
> +	.link_update = eth_macb_link_update,
> +	.dev_configure = eth_macb_dev_configure,
> +	.rx_queue_setup = macb_eth_rx_queue_setup,
> +	.tx_queue_setup = macb_eth_tx_queue_setup,
> +	.rx_queue_release = macb_eth_rx_queue_release,
> +	.tx_queue_release = macb_eth_tx_queue_release,
> +	.dev_start = eth_macb_dev_start,
> +	.dev_stop = eth_macb_dev_stop,
> +	.dev_close = eth_macb_dev_close,
> +	.stats_get = eth_macb_stats_get,
> +	.stats_reset = eth_macb_stats_reset,
> +	.rxq_info_get = macb_rxq_info_get,
> +	.txq_info_get = macb_txq_info_get,
> +	.dev_infos_get = eth_macb_dev_infos_get,
> +	.mtu_set = eth_macb_mtu_set,
> +	.dev_supported_ptypes_get = eth_macb_dev_supported_ptypes_get,
> +	.promiscuous_enable = eth_macb_promiscuous_enable,
> +	.promiscuous_disable = eth_macb_promiscuous_disable,
> +	.allmulticast_enable = eth_macb_allmulticast_enable,
> +	.allmulticast_disable = eth_macb_allmulticast_disable,
> +	.mac_addr_set = eth_macb_set_default_mac_addr,
> +};
> +
> +/**
> + * Callback used by rte_kvargs_process() during argument parsing.
> + *
> + * @param key
> + *   Pointer to the parsed key (unused).
> + * @param value
> + *   Pointer to the parsed value.
> + * @param extra_args
> + *   Pointer to the extra arguments which contains address of the
> + *   table of pointers to parsed interface names.
> + *
> + * @return
> + *   Always 0.
> + */
> +static int macb_devices_get(const char *key __rte_unused, const char *value,
> +							void *extra_args)
> +{
> +	struct macb_devices *devices = extra_args;
> +
> +	devices->names[devices->idx++] = value;
> +
> +	return 0;
> +}
> +
> +static int macb_phydrv_used_get(const char *key __rte_unused, const char *value,
> +							void *extra_args)
> +{
> +	bool *phydrv_used = extra_args;
> +
> +	*phydrv_used = (bool)atoi(value);
> +
> +	return 0;
> +}
> +
> +/**
> + * Init device.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, negative errno value on failure.
> + */
> +static int macb_dev_init(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	int ret;
> +
> +	dev->data->mac_addrs =
> +		rte_zmalloc("mac_addrs", RTE_ETHER_ADDR_LEN * MACB_MAC_ADDRS_MAX, 0);
> +	if (!dev->data->mac_addrs) {
> +		MACB_LOG(ERR, "Failed to allocate space for eth addrs");
> +		ret = -ENOMEM;
> +		goto out_free;
> +	}
> +
> +	/* Initialize local interrupt handle for current port. */
> +	priv->intr_handle =
> +		rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
> +	if (priv->intr_handle == NULL) {
> +		MACB_LOG(ERR, "Fail to allocate intr_handle");
> +		ret = -EFAULT;

When it fails, does it need to free 'dev->data->mac_addrs' at 'out_free'?

> +		goto out_free;
> +	}
> +
> +	dev->rx_pkt_burst = macb_eth_recv_pkts;
> +	dev->tx_pkt_burst = macb_eth_xmit_pkts;
> +	dev->dev_ops = &macb_ops;
> +	dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS | RTE_ETH_DEV_INTR_LSC;
> +
> +	/* for secondary processes, we don't initialise any further as primary
> +	 * has already done this work. Only check we don't need a different
> +	 * RX function
> +	 */
> +	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
> +		if (dev->data->scattered_rx)
> +			dev->rx_pkt_burst = &macb_eth_recv_scattered_pkts;
> +		return 0;
> +	}
> +
> +	bp->dev = dev;
> +
> +	if (!bp->iomem) {
> +		ret = macb_iomem_init(priv->name, bp, priv->physical_addr);
> +		if (ret) {
> +			MACB_LOG(ERR, "Failed to init device's iomem.");
> +			ret = -EFAULT;

When it fails, does it need 'rte_intr_instance_free' at 'out_free'?

> +			goto out_free;
> +		}
> +	}
> +
> +	if (rte_intr_fd_set(priv->intr_handle, bp->iomem->fd))

Same questions.

> +		return -rte_errno;
> +
> +	if (rte_intr_type_set(priv->intr_handle, RTE_INTR_HANDLE_UIO))

Same questions.

> +		return -rte_errno;
> +
> +	return 0;
> +out_free:
> +	return ret;
> +}
> +
> +static int macb_get_dev_pclk(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	char pclk_hz[CLK_STR_LEN];
> +	char *s;
> +	char filename[PATH_MAX];
> +
> +	snprintf(filename, PATH_MAX, "%s/%s/pclk_hz", MACB_PDEV_PATH, priv->name);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file) {
> +		MACB_LOG(ERR, "There is no macb_uio_pclk file!");
> +		return -ENFILE;
> +	}
> +
> +	memset(pclk_hz, 0, CLK_STR_LEN);
> +
> +	s = fgets(pclk_hz, CLK_STR_LEN, file);
> +	if (!s) {
> +		fclose(file);
> +		MACB_LOG(ERR, "get phy pclk error!");
> +		return -EINVAL;
> +	}
> +
> +	priv->pclk_hz = atol(pclk_hz);
> +	fclose(file);
> +	return 0;
> +}
> +
> +static const char *macb_phy_modes(phy_interface_t interface)
> +{
> +	switch (interface) {
> +	case MACB_PHY_INTERFACE_MODE_NA:
> +		return "";
> +	case MACB_PHY_INTERFACE_MODE_INTERNAL:
> +		return "internal";
> +	case MACB_PHY_INTERFACE_MODE_MII:
> +		return "mii";
> +	case MACB_PHY_INTERFACE_MODE_GMII:
> +		return "gmii";
> +	case MACB_PHY_INTERFACE_MODE_SGMII:
> +		return "sgmii";
> +	case MACB_PHY_INTERFACE_MODE_TBI:
> +		return "tbi";
> +	case MACB_PHY_INTERFACE_MODE_REVMII:
> +		return "rev-mii";
> +	case MACB_PHY_INTERFACE_MODE_RMII:
> +		return "rmii";
> +	case MACB_PHY_INTERFACE_MODE_RGMII:
> +		return "rgmii";
> +	case MACB_PHY_INTERFACE_MODE_RGMII_ID:
> +		return "rgmii-id";
> +	case MACB_PHY_INTERFACE_MODE_RGMII_RXID:
> +		return "rgmii-rxid";
> +	case MACB_PHY_INTERFACE_MODE_RGMII_TXID:
> +		return "rgmii-txid";
> +	case MACB_PHY_INTERFACE_MODE_RTBI:
> +		return "rtbi";
> +	case MACB_PHY_INTERFACE_MODE_SMII:
> +		return "smii";
> +	case MACB_PHY_INTERFACE_MODE_XGMII:
> +		return "xgmii";
> +	case MACB_PHY_INTERFACE_MODE_MOCA:
> +		return "moca";
> +	case MACB_PHY_INTERFACE_MODE_QSGMII:
> +		return "qsgmii";
> +	case MACB_PHY_INTERFACE_MODE_TRGMII:
> +		return "trgmii";
> +	case MACB_PHY_INTERFACE_MODE_100BASEX:
> +		return "100base-x";
> +	case MACB_PHY_INTERFACE_MODE_1000BASEX:
> +		return "1000base-x";
> +	case MACB_PHY_INTERFACE_MODE_2500BASEX:
> +		return "2500base-x";
> +	case MACB_PHY_INTERFACE_MODE_5GBASER:
> +		return "5gbase-r";
> +	case MACB_PHY_INTERFACE_MODE_RXAUI:
> +		return "rxaui";
> +	case MACB_PHY_INTERFACE_MODE_XAUI:
> +		return "xaui";
> +	case MACB_PHY_INTERFACE_MODE_10GBASER:
> +		return "10gbase-r";
> +	case MACB_PHY_INTERFACE_MODE_USXGMII:
> +		return "usxgmii";
> +	case MACB_PHY_INTERFACE_MODE_10GKR:
> +		return "10gbase-kr";
> +	default:
> +		return "unknown";
> +	}
> +}
> +
> +static int macb_get_phy_mode(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	char phy_mode[PHY_MODE_LEN];
> +	char *s;
> +	int i;
> +	char filename[PATH_MAX];
> +
> +	snprintf(filename, PATH_MAX, "%s/%s/phy_mode", MACB_PDEV_PATH, priv->name);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file) {
> +		MACB_LOG(ERR, "There is no phy_mode file!");
> +		return -ENFILE;
> +	}
> +
> +	memset(phy_mode, 0, PHY_MODE_LEN);
> +
> +	s = fgets(phy_mode, PHY_MODE_LEN, file);
> +	if (!s) {
> +		fclose(file);
> +		MACB_LOG(ERR, "get phy mode error!");
> +		return -EINVAL;
> +	}
> +
> +	priv->phy_interface = MACB_PHY_INTERFACE_MODE_MAX + 1;
> +	for (i = 0; i < MACB_PHY_INTERFACE_MODE_MAX; i++) {
> +		if (!strcasecmp(phy_mode, macb_phy_modes(i))) {
> +			priv->phy_interface = i;
> +			break;
> +		}
> +	}
> +
> +	if (priv->phy_interface > MACB_PHY_INTERFACE_MODE_MAX) {

Is fclose(file) missing here? Consider to close in a single place, after fgets.

> +		MACB_LOG(ERR, "Invalid phy_mode value: %s!", phy_mode);
> +		return -EINVAL;
> +	}
> +
> +	fclose(file);
> +	return 0;
> +}
> +
> +static int macb_get_physical_addr(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	char physical_addr[PHY_ADDR_LEN];
> +	char *s;
> +	char *stopstr;
> +	char filename[PATH_MAX];
> +
> +	snprintf(filename, PATH_MAX, "%s/%s/physical_addr", MACB_PDEV_PATH, priv->name);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file) {
> +		MACB_LOG(ERR, "There is no physical_addr file!");
> +		return -ENFILE;
> +	}
> +
> +	memset(physical_addr, 0, PHY_ADDR_LEN);
> +
> +	s = fgets(physical_addr, PHY_ADDR_LEN, file);
> +	if (!s) {
> +		fclose(file);
> +		MACB_LOG(ERR, "get physical address error!");
> +		return -EINVAL;
> +	}
> +
> +	priv->physical_addr = strtoul(physical_addr, &stopstr, 16);
> +	fclose(file);
> +	return 0;
> +}
> +
> +static int macb_get_dev_type(struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	char dev_type[DEV_TYPE_LEN];
> +	char *s;
> +	char filename[PATH_MAX];
> +	priv->dev_type = DEV_TYPE_DEFAULT;
> +
> +	snprintf(filename, PATH_MAX, "%s/%s/dev_type", MACB_PDEV_PATH, priv->name);
> +
> +	FILE *file = fopen(filename, "r");
> +	if (!file) {
> +		MACB_LOG(ERR, "There is no macb_dev_type file!");
> +		return -ENFILE;
> +	}
> +
> +	memset(dev_type, 0, DEV_TYPE_LEN);
> +
> +	s = fgets(dev_type, DEV_TYPE_LEN, file);
> +	if (!s) {
> +		fclose(file);
> +		MACB_LOG(ERR, "get dev type error!");
> +		return -EINVAL;
> +	}
> +	if (!strcmp(dev_type, OF_PHYTIUM_GEM1P0_MAC) ||
> +	    !strcmp(dev_type, ACPI_PHYTIUM_GEM1P0_MAC)) {
> +		priv->dev_type = DEV_TYPE_PHYTIUM_GEM1P0_MAC;
> +	} else if (!strcmp(dev_type, OF_PHYTIUM_GEM2P0_MAC)) {
> +		priv->dev_type = DEV_TYPE_PHYTIUM_GEM2P0_MAC;
> +	} else {

Is fclose(file) missing here? Consider to close in a single place, after fgets.

> +		MACB_LOG(ERR, "Unsupported device type: %s.", dev_type);
> +		return -EINVAL;
> +	}
> +
> +	fclose(file);
> +	return 0;
> +}
> +
> +static int macb_get_speed_info(struct rte_eth_dev *dev, char *speed_info)
> +{
> +	char filename[PATH_MAX];
> +	char *s;
> +	struct macb_priv *priv = dev->data->dev_private;
> +
> +	if (!speed_info) {
> +		MACB_LOG(ERR, "speed info is NULL.");
> +		return -ENOMEM;
> +	}
> +
> +	snprintf(filename, PATH_MAX, "%s/%s/speed_info", MACB_PDEV_PATH, priv->name);
> +	FILE *file = fopen(filename, "r");
> +	if (!file) {
> +		MACB_LOG(ERR, "There is no speed_info file!");
> +		return -ENFILE;
> +	}
> +
> +	s = fgets(speed_info, SPEED_INFO_LEN, file);
> +	if (!s) {
> +		fclose(file);
> +		MACB_LOG(ERR, "get speed info error!");
> +		return -EINVAL;
> +	}
> +
> +	fclose(file);
> +	return 0;
> +}
> +
> +static int macb_get_fixed_link_speed_info(struct rte_eth_dev *dev, struct macb *bp)
> +{
> +	char speed_info[SPEED_INFO_LEN];
> +	char *duplex = NULL;
> +	int ret = 0;
> +
> +	memset(speed_info, 0, SPEED_INFO_LEN);
> +
> +	ret = macb_get_speed_info(dev, speed_info);
> +	if (ret)
> +		return ret;
> +
> +	if (!strcmp(speed_info, "unknown")) {
> +		MACB_LOG(ERR, "speed info is unknown.");
> +		return -EINVAL;
> +	} else if (!strncmp(speed_info, "fixed-link", 10)) {
> +		bp->speed = atoi(speed_info + 11);
> +		duplex = strstr(speed_info, "full-duplex");
> +		if (duplex) {
> +			bp->duplex = DUPLEX_FULL;
> +			return 0;
> +		}
> +		duplex = strstr(speed_info, "half-duplex");
> +		if (duplex) {
> +			bp->duplex = DUPLEX_HALF;
> +			return 0;
> +		}
> +	} else {
> +		MACB_LOG(ERR, "Unsupported speed_info : %s.", speed_info);
> +		return -EINVAL;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int macb_update_fixed_link(struct rte_eth_dev *dev, struct macb *bp)
> +{
> +	int ret = 0;
> +	char speed_info[SPEED_INFO_LEN] = {0};
> +
> +	ret = macb_get_speed_info(dev, speed_info);
> +	if (ret)
> +		return ret;
> +
> +	if (!strncmp(speed_info, "fixed-link", 10))
> +		bp->fixed_link = true;
> +	return ret;
> +}
> +
> +/**
> + * Create device representing Ethernet port.
> + *
> + * @param ethdev_name
> + *   Pointer to the ethdev's name. example: net_macb0
> + *
> + * @param dev_name
> + *   Pointer to the port's name. example: 3200c000.ethernet
> + *
> + * @return
> + *   0 on success, negative error value otherwise.
> + */
> +static int macb_dev_create(struct rte_vdev_device *vdev, const char *ethdev_name,
> +			   const char *dev_name, bool phydrv_used)
> +{
> +	int ret;
> +	struct rte_eth_dev *eth_dev;
> +	struct macb_priv *priv;
> +	struct macb *bp;
> +	struct phy_device *phydev;
> +
> +	eth_dev = rte_eth_dev_allocate(ethdev_name);
> +	if (!eth_dev) {
> +		MACB_LOG(ERR, "failed to allocate eth_dev.");
> +		return -ENOMEM;
> +	}
> +
> +	if (eth_dev->data->dev_private)
> +		goto create_done;
> +
> +	priv = rte_zmalloc_socket(ethdev_name, sizeof(*priv), 0, rte_socket_id());
> +	if (!priv) {
> +		ret = -ENOMEM;
> +		goto out_free;
> +	}
> +
> +	bp = rte_zmalloc_socket(ethdev_name, sizeof(*bp), 0, rte_socket_id());
> +	if (!bp) {
> +		ret = -EPERM;

When it fails, does it need to free 'priv' at 'out_free'?

> +		goto out_free;
> +	}
> +
> +	phydev = rte_zmalloc_socket(ethdev_name, sizeof(*phydev), 0, rte_socket_id());
> +	if (!phydev) {
> +		ret = -EPERM;
> +		goto out_free_bp;
> +	}
> +
> +	eth_dev->device = &vdev->device;
> +	eth_dev->data->dev_private = priv;
> +	priv->bp = bp;
> +	strlcpy(priv->name, dev_name, sizeof(priv->name));
> +	bp->link = false;
> +	bp->fixed_link = false;
> +	bp->phydrv_used = phydrv_used;
> +	bp->phydev = phydev;
> +	phydev->bp = bp;
> +	priv->stopped = true;
> +
> +	ret = macb_get_dev_pclk(eth_dev);
> +	if (ret)
> +		goto out_free_phydev;
> +
> +	ret = macb_get_phy_mode(eth_dev);
> +	if (ret)
> +		goto out_free_phydev;
> +	bp->phy_interface = priv->phy_interface;
> +
> +	ret = macb_get_physical_addr(eth_dev);
> +	if (ret)
> +		goto out_free_phydev;
> +
> +	ret = macb_dev_init(eth_dev);
> +	if (ret)
> +		goto out_free_phydev;
> +
> +	ret = macb_get_dev_type(eth_dev);
> +	if (ret)
> +		goto out_free_phydev;
> +
> +	ret = macb_update_fixed_link(eth_dev, bp);
> +	if (ret)
> +		goto out_free_phydev;
> +
> +	if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII) {
> +		ret = macb_get_fixed_link_speed_info(eth_dev, bp);
> +		if (ret < 0) {
> +			bp->speed = SPEED_10000;
> +			bp->duplex = DUPLEX_FULL;
> +		}
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX) {
> +		bp->speed = SPEED_2500;
> +		bp->duplex = DUPLEX_FULL;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX) {
> +		bp->speed = SPEED_1000;
> +		bp->duplex = DUPLEX_FULL;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX) {
> +		bp->speed = SPEED_100;
> +		bp->duplex = DUPLEX_FULL;
> +	} else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_SGMII && bp->fixed_link) {
> +		ret = macb_get_fixed_link_speed_info(eth_dev, bp);
> +		if (ret < 0) {
> +			bp->speed = SPEED_1000;
> +			bp->duplex = DUPLEX_FULL;
> +		}
> +	} else {
> +		bp->speed = SPEED_UNKNOWN;
> +		bp->duplex = DUPLEX_UNKNOWN;
> +	}
> +
> +	macb_phy_auto_detect(eth_dev);
> +
> +	ret = rte_intr_callback_register(priv->intr_handle, macb_interrupt_handler,
> +									 (void *)eth_dev);
> +	if (ret) {
> +		MACB_LOG(ERR, "register callback failed.");
> +		goto out_free_phydev;
> +	}
> +
> +	rte_eth_dev_probing_finish(eth_dev);
> +create_done:
> +	return 0;
> +
> +out_free_phydev:
> +	rte_free(phydev);
> +out_free_bp:
> +	rte_free(bp);
> +
> +out_free:
> +	rte_eth_dev_release_port(eth_dev);
> +
> +	return ret;
> +}
> +
> +/**
> + * DPDK callback to remove virtual device.
> + *
> + * @param vdev
> + *   Pointer to the removed virtual device.
> + *
> + * @return
> + *   0 on success, negative error value otherwise.
> + */
> +static int rte_pmd_macb_remove(struct rte_vdev_device *vdev)
> +{
> +	uint16_t dev_id;
> +	int ret = 0;
> +
> +	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> +		return 0;
> +
> +	RTE_ETH_FOREACH_DEV(dev_id) {
> +		if (rte_eth_devices[dev_id].device != &vdev->device)
> +			continue;
> +		ret |= rte_eth_dev_close(dev_id);
> +	}
> +
> +	return ret == 0 ? 0 : -EIO;
> +}
> +
> +/**
> + * DPDK callback to register the virtual device.
> + *
> + * @param vdev
> + *   Pointer to the virtual device.
> + *
> + * @return
> + *   0 on success, negative error value otherwise.
> + */
> +static int rte_pmd_macb_probe(struct rte_vdev_device *vdev)
> +{
> +	struct rte_kvargs *kvlist;
> +	struct macb_devices devices;
> +	bool phydrv_used = true;
> +	int ret = -EINVAL;
> +	uint32_t i, dev_num;
> +	const char *params;
> +	enum rte_iova_mode iova_mode;
> +	char ethdev_name[RTE_DEV_NAME_MAX_LEN] = "";
> +	const char *vdev_name;
> +	struct rte_eth_dev *eth_dev;
> +
> +	vdev_name = rte_vdev_device_name(vdev);
> +
> +	/* secondary process probe */
> +	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
> +		eth_dev = rte_eth_dev_attach_secondary(vdev_name);
> +		if (!eth_dev) {
> +			MACB_LOG(ERR, "Secondary failed to probe eth_dev.");
> +			return -1;
> +		}
> +
> +		if (vdev->device.numa_node == SOCKET_ID_ANY)
> +			vdev->device.numa_node = rte_socket_id();
> +		eth_dev->device = &vdev->device;
> +		rte_eth_dev_probing_finish(eth_dev);
> +
> +		return 0;
> +	}
> +
> +	iova_mode = rte_eal_iova_mode();
> +	if (iova_mode != RTE_IOVA_PA) {
> +		MACB_LOG(ERR, "Expecting 'PA' IOVA mode but current mode is 'VA', not "
> +					  "initializing");
> +		return -EINVAL;
> +	}
> +
> +	params = rte_vdev_device_args(vdev);
> +	if (!params) {
> +		MACB_LOG(ERR, "failed to get the args.");
> +		return -EINVAL;
> +	}
> +
> +	kvlist = rte_kvargs_parse(params, valid_args);
> +	if (!kvlist) {
> +		MACB_LOG(ERR, "failed to parse the kvargs.");
> +		return -EINVAL;
> +	}
> +
> +	rte_kvargs_process(kvlist, MACB_USE_PHYDRV_ARG, macb_phydrv_used_get, &phydrv_used);
> +
> +	dev_num = rte_kvargs_count(kvlist, MACB_DEVICE_NAME_ARG);
> +
> +	/* compatibility support */
> +	if (!strcmp(vdev_name, "net_macb")) {
> +		if (dev_num > MACB_MAX_PORT_NUM) {
> +			ret = -EINVAL;
> +			MACB_LOG(ERR, "number of devices exceeded. Maximum value: %d.",
> +				 MACB_MAX_PORT_NUM);
> +			goto out_free_kvlist;
> +		}
> +	} else {
> +		if (dev_num != 1) {
> +			ret = -EINVAL;
> +			MACB_LOG(ERR, "Error args: one vdev to one device.");
> +			goto out_free_kvlist;
> +		}
> +	}
> +
> +	devices.idx = 0;
> +	rte_kvargs_process(kvlist, MACB_DEVICE_NAME_ARG, macb_devices_get, &devices);
> +
> +	MACB_INFO("Phytium mac driver v%s", MACB_DRIVER_VERSION);
> +
> +	for (i = 0; i < dev_num; i++) {
> +		if (dev_num > 1)
> +			snprintf(ethdev_name, RTE_DEV_NAME_MAX_LEN, "%s%d", vdev_name, i);
> +		else
> +			snprintf(ethdev_name, RTE_DEV_NAME_MAX_LEN, "%s", vdev_name);
> +
> +		ret = macb_dev_create(vdev, ethdev_name, devices.names[i], phydrv_used);
> +		if (ret) {
> +			MACB_LOG(ERR, "failed to create device.");
> +			goto out_cleanup;
> +		}
> +
> +		macb_dev_num++;
> +	}
> +
> +	rte_kvargs_free(kvlist);
> +	return 0;
> +
> +out_cleanup:
> +	rte_pmd_macb_remove(vdev);
> +
> +out_free_kvlist:
> +	rte_kvargs_free(kvlist);
> +
> +	return ret;
> +}
> +
> +static struct rte_vdev_driver pmd_macb_drv = {
> +	.probe = rte_pmd_macb_probe,
> +	.remove = rte_pmd_macb_remove,
> +};
> +
> +RTE_PMD_REGISTER_KMOD_DEP(net_macb, "macb_uio");
> +RTE_PMD_REGISTER_VDEV(net_macb, pmd_macb_drv);
> +RTE_PMD_REGISTER_PARAM_STRING(net_macb,
> +					MACB_DEVICE_NAME_ARG "=<string> "
> +					MACB_USE_PHYDRV_ARG "=<int>");
> +
> +RTE_INIT(macb_init_log)
> +{
> +	if (macb_log_initialized)
> +		return;
> +
> +	macb_logtype = rte_log_register("pmd.net.macb");
> +
> +	macb_log_initialized = 1;
> +}
> diff --git a/drivers/net/macb/macb_ethdev.h b/drivers/net/macb/macb_ethdev.h
> new file mode 100644
> index 0000000..e1abf60
> --- /dev/null
> +++ b/drivers/net/macb/macb_ethdev.h
> @@ -0,0 +1,75 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_ETHDEV_H_
> +#define _MACB_ETHDEV_H_
> +
> +#include <rte_interrupts.h>
> +#include <dlfcn.h>
> +#include "base/macb_common.h"
> +#include "macb_log.h"
> +
> +#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
> +#define ETH_MIN_MTU	68		/* Min IPv4 MTU per RFC791	*/
> +
> +#define CLK_STR_LEN 64
> +#define PHY_MODE_LEN 64
> +#define PHY_ADDR_LEN 64
> +#define DEV_TYPE_LEN 64
> +#define SPEED_INFO_LEN 64
> +#define MAX_PHY_AD_NUM 32
> +#define PHY_ID_OFFSET 16
> +
> +#define GEM_MTU_MIN_SIZE	ETH_MIN_MTU
> +
> +#ifndef min
> +#define min(x, y) ({ \
> +		typeof(x) _x = (x); \
> +		typeof(y) _y = (y); \
> +		(_x < _y) ? _x : _y; \
> +		})
> +#endif
> +
> +/*
> + * Custom phy driver need to be stated here.
> + */
> +extern struct phy_driver genphy_driver;
> +
> +/*internal macb 10G PHY*/
> +extern struct phy_driver macb_usxgmii_pcs_driver;
> +/*internal macb gbe PHY*/
> +extern struct phy_driver macb_gbe_pcs_driver;
> +
> +#define VLAN_TAG_SIZE    4
> +#define RTE_ETHER_CRC_LEN   4 /**< Length of Ethernet CRC. */
> +#define RTE_ETHER_TYPE_LEN 2
> +#define RTE_ETHER_ADDR_LEN 6
> +#define RTE_ETHER_HDR_LEN   \
> +	(RTE_ETHER_ADDR_LEN * 2 + \
> +	 RTE_ETHER_TYPE_LEN) /**< Length of Ethernet header. */
> +#define MACB_ETH_OVERHEAD (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + \
> +				VLAN_TAG_SIZE)
> +
> +#define MACB_RX_INT_FLAGS	(MACB_BIT(RCOMP) | MACB_BIT(ISR_ROVR))
> +#define MACB_TX_ERR_FLAGS	(MACB_BIT(ISR_TUND)			\
> +					| MACB_BIT(ISR_RLE)		\
> +					| MACB_BIT(TXERR))
> +#define MACB_TX_INT_FLAGS	(MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)	\
> +					| MACB_BIT(TXUBR))
> +
> +struct macb_priv {
> +	struct macb *bp;
> +	uint32_t port_id;
> +	uint64_t pclk_hz;
> +	phys_addr_t physical_addr;
> +	uint32_t dev_type;
> +	bool stopped;
> +	netdev_features_t hw_features;
> +	netdev_features_t phy_interface;
> +	struct rte_eth_stats prev_stats;
> +	struct rte_intr_handle *intr_handle;
> +	char name[RTE_ETH_NAME_MAX_LEN];
> +};
> +
> +#endif /* _MACB_ETHDEV_H_ */
> diff --git a/drivers/net/macb/macb_log.h b/drivers/net/macb/macb_log.h
> new file mode 100644
> index 0000000..b13d73a
> --- /dev/null
> +++ b/drivers/net/macb/macb_log.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_LOG_H_
> +#define _MACB_LOG_H_
> +
> +/* Current log type. */
> +extern int macb_logtype;
> +
> +#define RTE_LOGTYPE_MACB macb_logtype
> +#define MACB_LOG(level, fmt, ...) \
> +	RTE_LOG_LINE(level, MACB, "%s(): " fmt, \
> +		__func__, ##__VA_ARGS__)
> +
> +#define MACB_INFO(fmt, ...) \
> +	RTE_LOG_LINE(INFO, MACB, fmt, ##__VA_ARGS__)
> +
> +#endif /*_MACB_LOG_H_ */
> diff --git a/drivers/net/macb/macb_rxtx.c b/drivers/net/macb/macb_rxtx.c
> new file mode 100644
> index 0000000..e83d650
> --- /dev/null
> +++ b/drivers/net/macb/macb_rxtx.c
> @@ -0,0 +1,1391 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#include <rte_bus_vdev.h>
> +#include <ethdev_driver.h>
> +#include <rte_kvargs.h>
> +#include <rte_string_fns.h>
> +#include <rte_vect.h>
> +
> +#include <fcntl.h>
> +#include <linux/ethtool.h>
> +#include <linux/sockios.h>
> +#include <net/if.h>
> +#include <net/if_arp.h>
> +#include <rte_ether.h>
> +#include <stdio.h>
> +#include <sys/ioctl.h>
> +#include <sys/param.h>
> +#include <sys/socket.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +
> +#include "macb_rxtx.h"
> +
> +#define MACB_MAX_TX_BURST    32
> +#define MACB_TX_MAX_FREE_BUF_SZ 64
> +
> +/* Default RS bit threshold values */
> +#ifndef MACB_DEFAULT_TX_RS_THRESH
> +#define MACB_DEFAULT_TX_RS_THRESH   32
> +#endif
> +#ifndef MACB_DEFAULT_TX_FREE_THRESH
> +#define MACB_DEFAULT_TX_FREE_THRESH 32
> +#endif
> +
> +uint16_t macb_eth_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
> +							uint16_t nb_pkts)
> +{
> +	struct macb_tx_queue *queue;
> +	struct macb *bp;
> +	struct macb_tx_entry *macb_txe;
> +	uint32_t tx_head, tx_tail;
> +	struct rte_mbuf *tx_pkt;
> +	struct rte_mbuf *m_seg;
> +	uint16_t nb_tx;
> +	uint32_t tx_first;
> +	uint32_t tx_last;
> +	uint64_t buf_dma_addr;
> +	uint16_t free_txds;
> +	u32 ctrl;
> +	struct macb_dma_desc *txdesc;
> +
> +	queue = (struct macb_tx_queue *)tx_queue;
> +	bp = queue->bp;
> +
> +	macb_reclaim_txd(queue);
> +	tx_head = queue->tx_head;
> +	tx_tail = queue->tx_tail;
> +	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
> +		tx_pkt = *tx_pkts++;
> +		tx_first = tx_tail;
> +		tx_last = tx_tail + tx_pkt->nb_segs - 1;

Has this code been tested against the case where a packet comprising N segments
is sent via a TxQ comprising M descriptors and N is wittingly greater than M?

> +		tx_last = macb_tx_ring_wrap(bp, tx_last);
> +
> +		/* Make hw descriptor updates visible to CPU */
> +		rte_rmb();
> +
> +		if (unlikely(tx_head == tx_tail))
> +			free_txds = bp->tx_ring_size - 1;
> +		else if (tx_head > tx_tail)
> +			free_txds = tx_head - tx_tail - 1;
> +		else
> +			free_txds = bp->tx_ring_size - (tx_tail - tx_head) - 1;
> +
> +		if (free_txds < tx_pkt->nb_segs) {
> +			if (nb_tx == 0)
> +				return 0;
> +			goto end_of_tx;
> +		}
> +
> +		m_seg = tx_pkt;
> +		do {
> +			txdesc = macb_tx_desc(queue, tx_tail);
> +			macb_txe = macb_tx_entry(queue, tx_tail);
> +			if (likely(macb_txe->mbuf != NULL))
> +				rte_pktmbuf_free_seg(macb_txe->mbuf);
> +			macb_txe->mbuf = m_seg;
> +
> +			queue->stats.tx_bytes += m_seg->data_len;
> +			ctrl = (u32)m_seg->data_len | MACB_BIT(TX_USED);

In 'rte_mbuf', 'data_len' is 16-bit, whereas 'MACB_TX_FRMLEN_SIZE' is 11-bit.
Has this code been tested against segment size >= 2048?

> +			if (unlikely(tx_tail == (queue->nb_tx_desc - 1)))
> +				ctrl |= MACB_BIT(TX_WRAP);
> +
> +			if (likely(tx_tail == tx_last))
> +				ctrl |= MACB_BIT(TX_LAST);
> +
> +			buf_dma_addr = rte_mbuf_data_iova(m_seg);
> +			/* Set TX buffer descriptor */
> +			macb_set_addr(bp, txdesc, buf_dma_addr);
> +			txdesc->ctrl = ctrl;
> +			m_seg = m_seg->next;
> +
> +			tx_tail = macb_tx_ring_wrap(bp, ++tx_tail);
> +		} while (unlikely(m_seg != NULL));
> +
> +		while (unlikely(tx_last != tx_first)) {
> +			txdesc = macb_tx_desc(queue, tx_last);
> +			txdesc->ctrl &= ~MACB_BIT(TX_USED);
> +			tx_last = macb_tx_ring_wrap(bp, --tx_last);
> +		}
> +
> +		txdesc = macb_tx_desc(queue, tx_last);
> +		rte_wmb();
> +		txdesc->ctrl &= ~MACB_BIT(TX_USED);
> +
> +		queue->stats.tx_packets++;
> +	}
> +
> +end_of_tx:
> +	macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
> +	queue->tx_tail = tx_tail;
> +
> +	return nb_tx;
> +}
> +
> +uint16_t macb_eth_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
> +							uint16_t nb_pkts)
> +{
> +	struct macb_rx_queue *rxq;
> +	unsigned int len;
> +	unsigned int entry, next_entry;
> +	struct macb_dma_desc *desc, *ndesc;
> +	uint16_t nb_rx;
> +	struct macb *bp;
> +	struct rte_mbuf *rxm;
> +	struct rte_mbuf *nmb;
> +	struct macb_rx_entry *rxe, *rxn;
> +	uint64_t dma_addr;
> +	uint8_t rxused_v[MACB_LOOK_AHEAD];
> +	uint8_t nb_rxused;
> +	int i;
> +
> +	nb_rx = 0;
> +	rxq = rx_queue;
> +	bp = rxq->bp;
> +
> +	while (nb_rx < nb_pkts) {
> +		u32 ctrl;
> +		bool rxused;


> +		struct rte_ether_hdr *eth_hdr;
1. Const?
2. Perhaps move this to the inner loop where it belongs.

> +		uint16_t ether_type;
Also belongs in the inner loop.

> +
> +		entry = macb_rx_ring_wrap(bp, rxq->rx_tail);
> +		desc = macb_rx_desc(rxq, entry);
> +
> +		/* Make hw descriptor updates visible to CPU */
> +		rte_rmb();
> +
> +		rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
> +		if (!rxused)
> +			break;
> +
> +		for (i = 0; i < MACB_LOOK_AHEAD; i++) {
> +			desc = macb_rx_desc(rxq, (entry + i));
> +			rxused_v[i] = (desc->addr & MACB_BIT(RX_USED)) ? 1 : 0;
> +		}
> +
> +		/* Ensure ctrl is at least as up-to-date as rxused */
> +		rte_rmb();
> +
> +		/* Compute how many status bits were set */
> +		for (i = 0, nb_rxused = 0; i < MACB_LOOK_AHEAD; i++) {
> +			if (unlikely(rxused_v[i] == 0))
> +				break;
> +			nb_rxused += rxused_v[i];
> +		}
> +
> +		/* Translate descriptor info to mbuf parameters */
> +		for (i = 0; i < nb_rxused; i++) {
> +			rxe = macb_rx_entry(rxq, (entry + i));
> +			desc = macb_rx_desc(rxq, (entry + i));
> +			ctrl = desc->ctrl;
> +			rxq->rx_tail++;
> +			rte_prefetch0(macb_rx_entry(rxq, rxq->rx_tail)->mbuf);
> +
> +			if (unlikely((ctrl & (MACB_BIT(RX_SOF) | MACB_BIT(RX_EOF)))
> +				!= (MACB_BIT(RX_SOF) | MACB_BIT(RX_EOF)))) {
> +				MACB_LOG(ERR, "not whole frame pointed by descriptor");
> +				rxq->rx_tail = macb_rx_ring_wrap(bp, rxq->rx_tail);
> +				rxq->stats.rx_dropped++;
> +
> +				desc->ctrl = 0;
> +				rte_wmb();
> +				desc->addr &= ~MACB_BIT(RX_USED);
> +				continue;
> +			}
> +
> +			nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
> +			if (unlikely(!nmb)) {
> +				MACB_LOG(ERR, "RX mbuf alloc failed port_id=%u queue_id=%u",
> +					 (unsigned int)rxq->port_id, (unsigned int)rxq->queue_id);

IMHO, it's odd to log an error on datapath. 'rx_mbuf_alloc_failed' is enough.

> +				rxq->rx_tail = macb_rx_ring_wrap(bp, rxq->rx_tail);
> +				rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;
> +				rxq->stats.rx_dropped++;

Why increment 'rx_dropped' on refill failure?

> +
> +				desc->ctrl = 0;
> +				rte_wmb();
> +				desc->addr &= ~MACB_BIT(RX_USED);
> +				goto out;

Why go out without having visited the rest of the received packets? Perhaps I
just misunderstand the logic of the driver.

> +			}
> +			nmb->data_off = RTE_PKTMBUF_HEADROOM + MACB_RX_DATA_OFFSET;
> +
> +			next_entry = macb_rx_ring_wrap(bp, (rxq->rx_tail + MACB_NEXT_FETCH));
> +			rxn = macb_rx_entry(rxq, next_entry);
> +			rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
> +			ndesc = macb_rx_desc(rxq, next_entry);
> +
> +			/*
> +			 * When next RX descriptor is on a cache-line boundary,
> +			 * prefetch the next 2 RX descriptors.
> +			 */
> +			if ((next_entry & 0x3) == 0)
> +				rte_prefetch0(ndesc);
> +
> +			rxm = rxe->mbuf;
> +			rxe->mbuf = nmb;
> +
> +			len = (ctrl & bp->rx_frm_len_mask) - rxq->crc_len;
> +			rxq->stats.rx_packets++;
> +			rxq->stats.rx_bytes += len;
> +
> +			dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
> +			rxm->nb_segs = 1;
> +			rxm->next = NULL;
> +			rxm->pkt_len = len;
> +			rxm->data_len = len;
> +			rxm->port = rxq->port_id;
> +			rxm->ol_flags = RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD;

This sets the flags unconditionally, but the actual offload can be either
enabled or disabled in 'macb_eth_rx_init'. Is this consistent?

Why doesn't the code parse 'GEM_RX_CSUM' bits?

> +
> +			eth_hdr = rte_pktmbuf_mtod(rxm, struct rte_ether_hdr *);
> +			ether_type = eth_hdr->ether_type;
> +
> +			if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))

Consider to use 'RTE_BE16' for static constants like 'RTE_ETHER_TYPE_IPV4'
instead of 'rte_cpu_to_be_16'.

> +				rxm->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4;
> +			else if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6))

Same here.

> +				rxm->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6;
> +			else
> +				rxm->packet_type = RTE_PTYPE_UNKNOWN;

IMHO, this whole EtherType section just duplicates 'rte_net_get_ptype'.

> +
> +			/*
> +			 * Store the mbuf address into the next entry of the array
> +			 * of returned packets.
> +			 */
> +			rx_pkts[nb_rx++] = rxm;
> +
> +			if (unlikely(rxq->rx_tail == rxq->nb_rx_desc)) {
> +				dma_addr |= MACB_BIT(RX_WRAP);
> +				rxq->rx_tail = 0;
> +			}
> +
> +			desc->ctrl = 0;
> +			/* Setting addr clears RX_USED and allows reception,

/*
  * Proper multiline comment style keeps
  * the first slash on a separate line.
  */

> +			 * make sure ctrl is cleared first to avoid a race.
> +			 */
> +			rte_wmb();
> +			macb_set_addr(bp, desc, dma_addr);
> +		}
> +
> +		if (nb_rxused != MACB_LOOK_AHEAD)
> +			break;
> +	}
> +

Is it possible to separate processing received packets from refill and make it
batch-oriented? Above seems to refill packet-by-packet, however many drivers
would prefer to just do 'rte_mbuf_raw_alloc_bulk' in the end and refill a batch.
Why are packet processing and refill so intertwined in the above loop?

> +out:
> +	return nb_rx;
> +}
> +
> +uint16_t macb_eth_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
> +									  uint16_t nb_pkts)
> +{
> +	struct macb_rx_queue *rxq;
> +	unsigned int len;
> +	unsigned int entry, next_entry;
> +	struct macb_dma_desc *desc, *ndesc;
> +	uint16_t nb_rx;
> +	struct macb *bp;
> +	struct rte_mbuf *first_seg;
> +	struct rte_mbuf *last_seg;
> +	struct rte_mbuf *rxm;
> +	struct rte_mbuf *nmb;
> +	struct macb_rx_entry *rxe, *rxn;
> +	uint64_t dma_addr;
> +	uint8_t rxused_v[MACB_LOOK_AHEAD];
> +	uint8_t nb_rxused;
> +	uint16_t data_bus_width_mask;
> +	int i;
> +
> +	nb_rx = 0;
> +	rxq = rx_queue;
> +	bp = rxq->bp;
> +
> +	/*
> +	 * Retrieve RX context of current packet, if any.
> +	 */

Perhaps no need to make this multiline when it fits in a single line.

> +	first_seg = rxq->pkt_first_seg;
> +	last_seg = rxq->pkt_last_seg;
> +	data_bus_width_mask = MACB_DATA_BUS_WIDTH_MASK(bp->data_bus_width);
> +
> +	while (nb_rx < nb_pkts) {
> +		u32 ctrl;
> +		bool rxused;

> +		struct rte_ether_hdr *eth_hdr;
Same here. Const? May be move it to the inner loop.

> +		uint16_t ether_type;
Also belongs in the inner loop.

> +
> +		entry = macb_rx_ring_wrap(bp, rxq->rx_tail);
> +		desc = macb_rx_desc(rxq, entry);
> +
> +		/* Make hw descriptor updates visible to CPU */
> +		rte_rmb();
> +
> +		rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
> +		if (!rxused)
> +			break;
> +
> +		for (i = 0; i < MACB_LOOK_AHEAD; i++) {
> +			desc = macb_rx_desc(rxq, (entry + i));
> +			rxused_v[i] = (desc->addr & MACB_BIT(RX_USED)) ? 1 : 0;
> +		}
> +
> +		/* Ensure ctrl is at least as up-to-date as rxused */
> +		rte_rmb();
> +
> +		/* Compute how many status bits were set */
> +		for (i = 0, nb_rxused = 0; i < MACB_LOOK_AHEAD; i++) {
> +			if (unlikely(rxused_v[i] == 0))
> +				break;
> +			nb_rxused += rxused_v[i];
> +		}
> +
> +		/* Translate descriptor info to mbuf parameters */
> +		for (i = 0; i < nb_rxused; i++) {
> +			rxe = macb_rx_entry(rxq, (entry + i));
> +			desc = macb_rx_desc(rxq, (entry + i));
> +			ctrl = desc->ctrl;
> +			rxq->rx_tail++;
> +			rte_prefetch0(macb_rx_entry(rxq, rxq->rx_tail)->mbuf);
> +
> +			nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
> +			if (unlikely(!nmb)) {
> +				MACB_LOG(ERR, "RX mbuf alloc failed port_id=%u queue_id=%u",
> +					 (unsigned int)rxq->port_id, (unsigned int)rxq->queue_id);
> +				rxq->rx_tail = macb_rx_ring_wrap(bp, rxq->rx_tail);
> +				rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;
> +				rxq->stats.rx_dropped++;
> +
> +				desc->ctrl = 0;
> +				rte_wmb();
> +				desc->addr &= ~MACB_BIT(RX_USED);
> +				goto out;
> +			}
> +			nmb->data_off = RTE_PKTMBUF_HEADROOM + MACB_RX_DATA_OFFSET;
> +
> +			next_entry = macb_rx_ring_wrap(bp, (rxq->rx_tail + MACB_NEXT_FETCH));
> +			rxn = macb_rx_entry(rxq, next_entry);
> +			rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
> +			ndesc = macb_rx_desc(rxq, next_entry);
> +
> +			/*
> +			 * When next RX descriptor is on a cache-line boundary,
> +			 * prefetch the next 2 RX descriptors.
> +			 */
> +			if ((next_entry & 0x3) == 0)
> +				rte_prefetch0(ndesc);
> +
> +			rxm = rxe->mbuf;
> +			rxe->mbuf = nmb;
> +
> +			dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
> +			if (unlikely(rxq->rx_tail == rxq->nb_rx_desc)) {
> +				dma_addr |= MACB_BIT(RX_WRAP);
> +				rxq->rx_tail = 0;
> +			}
> +			desc->ctrl = 0;
> +			/* Setting addr clears RX_USED and allows reception,
> +			 * make sure ctrl is cleared first to avoid a race.
> +			 */
> +			rte_wmb();
> +			macb_set_addr(bp, desc, dma_addr);
> +
> +			len = ctrl & bp->rx_frm_len_mask;
> +			rxq->stats.rx_bytes += len;
> +
> +			/*
> +			 * If this is the first buffer of the received packet,
> +			 * set the pointer to the first mbuf of the packet and
> +			 * initialize its context.
> +			 * Otherwise, update the total length and the number of segments
> +			 * of the current scattered packet, and update the pointer to
> +			 * the last mbuf of the current packet.
> +			 */
> +			if (!first_seg) {
> +				first_seg = rxm;
> +				first_seg->nb_segs = 1;
> +				first_seg->pkt_len =
> +					len ? len : (bp->rx_buffer_size - MACB_RX_DATA_OFFSET -
> +					(RTE_PKTMBUF_HEADROOM & data_bus_width_mask));
> +				rxm->data_len = first_seg->pkt_len;
> +
> +				eth_hdr = rte_pktmbuf_mtod(rxm, struct rte_ether_hdr *);
> +				ether_type = eth_hdr->ether_type;
Does the code rule out reading past the buffer?

> +
> +				if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))
Same here: perhaps use 'RTE_BE16' instead of 'rte_cpu_to_be_16'.

> +					rxm->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4;
> +				else if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6))
> +					rxm->packet_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6;
> +				else
> +					rxm->packet_type = RTE_PTYPE_UNKNOWN;
> +			} else {
> +				rxm->data_len =
> +					len ? (len - first_seg->pkt_len) : bp->rx_buffer_size;
> +				rxm->data_off = RTE_PKTMBUF_HEADROOM & ~data_bus_width_mask;
> +				if (likely(rxm->data_len > 0)) {
> +					first_seg->pkt_len += rxm->data_len;
> +					first_seg->nb_segs++;
> +					last_seg->next = rxm;
> +				}
> +			}
> +
> +			/*
> +			 * If this is not the last buffer of the received packet,
> +			 * update the pointer to the last mbuf of the current scattered
> +			 * packet and continue to parse the RX ring.
> +			 */
> +			if (!(ctrl & MACB_BIT(RX_EOF))) {
> +				last_seg = rxm;
> +				continue;
> +			}
> +
> +			/*
> +			 * This is the last buffer of the received packet.
> +			 * If the CRC is not stripped by the hardware:
> +			 *   - Subtract the CRC	length from the total packet length.
> +			 *   - If the last buffer only contains the whole CRC or a part
> +			 *     of it, free the mbuf associated to the last buffer.
> +			 *     If part of the CRC is also contained in the previous
> +			 *     mbuf, subtract the length of that CRC part from the
> +			 *     data length of the previous mbuf.
> +			 */
> +			rxm->next = NULL;
> +			if (unlikely(rxq->crc_len > 0)) {
> +				first_seg->pkt_len -= RTE_ETHER_CRC_LEN;
> +				if (rxm->data_len <= RTE_ETHER_CRC_LEN) {
> +					rte_pktmbuf_free_seg(rxm);
> +					first_seg->nb_segs--;
> +					last_seg->data_len = (uint16_t)(last_seg->data_len -
> +									(RTE_ETHER_CRC_LEN - len));
> +					last_seg->next = NULL;
> +				} else {
> +					rxm->data_len = rxm->data_len - RTE_ETHER_CRC_LEN;
> +				}
> +			}
> +
> +			first_seg->port = rxq->port_id;
> +			first_seg->ol_flags = RTE_MBUF_F_RX_IP_CKSUM_GOOD |
> +					      RTE_MBUF_F_RX_L4_CKSUM_GOOD;
> +			/*
> +			 * Store the mbuf address into the next entry of the array
> +			 * of returned packets.
> +			 */
> +			rx_pkts[nb_rx++] = first_seg;
> +			rxq->stats.rx_packets++;
> +			/*
> +			 * Setup receipt context for a new packet.
> +			 */
> +			first_seg = NULL;
> +			last_seg = NULL;
> +		}
> +
> +		if (nb_rxused != MACB_LOOK_AHEAD)
> +			break;
> +	}
> +
> +out:
> +	/*
> +	 * Save receive context.
> +	 */
> +	rxq->pkt_first_seg = first_seg;
> +	rxq->pkt_last_seg = last_seg;
> +
> +	return nb_rx;
> +}
> +
> +void __rte_cold macb_tx_queue_release_mbufs(struct macb_tx_queue *txq)
> +{
> +	unsigned int i;
> +
> +	if (txq->tx_sw_ring != NULL) {
> +		for (i = 0; i < txq->nb_tx_desc; i++) {
> +			if (txq->tx_sw_ring[i].mbuf != NULL) {
> +				rte_pktmbuf_free_seg(txq->tx_sw_ring[i].mbuf);
> +				txq->tx_sw_ring[i].mbuf = NULL;
> +			}
> +		}
> +	}
> +}
> +
> +static void __rte_cold macb_tx_queue_release(struct macb_tx_queue *txq)
> +{
> +	if (txq != NULL) {
> +		macb_tx_queue_release_mbufs(txq);
> +		rte_free(txq->tx_sw_ring);
> +		rte_free(txq);
> +	}
> +}
> +
> +void __rte_cold macb_eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
> +{
> +	macb_tx_queue_release(dev->data->tx_queues[qid]);
> +}
> +
> +void __rte_cold macb_reset_tx_queue(struct macb_tx_queue *txq, struct rte_eth_dev *dev)
> +{
> +	struct macb_tx_entry *txe = txq->tx_sw_ring;
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	uint16_t i;
> +	struct macb_dma_desc *desc = NULL;
> +
> +	/* Zero out HW ring memory */
> +	for (i = 0; i < txq->nb_tx_desc; i++) {
> +		desc = macb_tx_desc(txq, i);
> +		macb_set_addr(bp, desc, 0);
> +		desc->ctrl = MACB_BIT(TX_USED);
> +	}
> +
> +	desc->ctrl |= MACB_BIT(TX_WRAP);
> +	txq->tx_head = 0;
> +	txq->tx_tail = 0;
> +	memset((void *)&txq->stats, 0, sizeof(struct macb_tx_queue_stats));
> +
> +	/* Initialize ring entries */
> +	for (i = 0; i < txq->nb_tx_desc; i++)
> +		txe[i].mbuf = NULL;
> +}
> +
> +static void __rte_cold
> +macb_set_tx_function(struct macb_tx_queue *txq, struct rte_eth_dev *dev)
> +{
> +	if (txq->tx_rs_thresh >= MACB_MAX_TX_BURST) {
> +		if (txq->tx_rs_thresh <= MACB_TX_MAX_FREE_BUF_SZ &&
> +		    (rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)) {
> +			MACB_LOG(DEBUG, "Vector tx enabled.");
> +			dev->tx_pkt_burst = macb_eth_xmit_pkts_vec;
> +		}
> +	} else {
> +		dev->tx_pkt_burst = macb_eth_xmit_pkts;
> +	}
> +}
> +
> +int __rte_cold macb_eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
> +							uint16_t nb_desc, unsigned int socket_id,
> +							const struct rte_eth_txconf *tx_conf)
> +{
> +	const struct rte_memzone *tz;
> +	struct macb_tx_queue *txq;
> +	uint32_t size;
> +	struct macb_priv *priv;
> +	struct macb *bp;
> +	uint16_t tx_free_thresh, tx_rs_thresh;
> +
> +	priv = dev->data->dev_private;
> +	bp = priv->bp;
> +	/*
> +	 * The following two parameters control the setting of the RS bit on
> +	 * transmit descriptors.
> +	 * TX descriptors will have their RS bit set after txq->tx_rs_thresh
> +	 * descriptors have been used.
> +	 * The TX descriptor ring will be cleaned after txq->tx_free_thresh
> +	 * descriptors are used or if the number of descriptors required
> +	 * to transmit a packet is greater than the number of free TX
> +	 * descriptors.
> +	 * The following constraints must be satisfied:
> +	 *  tx_rs_thresh must be greater than 0.
> +	 *  tx_rs_thresh must be less than the size of the ring minus 2.
> +	 *  tx_rs_thresh must be less than or equal to tx_free_thresh.
> +	 *  tx_rs_thresh must be a divisor of the ring size.
> +	 *  tx_free_thresh must be greater than 0.
> +	 *  tx_free_thresh must be less than the size of the ring minus 3.
> +	 *  tx_free_thresh + tx_rs_thresh must not exceed nb_desc.
> +	 * One descriptor in the TX ring is used as a sentinel to avoid a
> +	 * H/W race condition, hence the maximum threshold constraints.
> +	 * When set to zero use default values.
> +	 */
> +	tx_free_thresh = (uint16_t)((tx_conf->tx_free_thresh) ?
> +			tx_conf->tx_free_thresh : MACB_DEFAULT_TX_FREE_THRESH);
> +	/* force tx_rs_thresh to adapt an aggressive tx_free_thresh */
> +	tx_rs_thresh = (MACB_DEFAULT_TX_RS_THRESH + tx_free_thresh > nb_desc) ?
> +			nb_desc - tx_free_thresh : MACB_DEFAULT_TX_RS_THRESH;
> +	if (tx_conf->tx_rs_thresh > 0)
> +		tx_rs_thresh = tx_conf->tx_rs_thresh;
> +	if (tx_rs_thresh + tx_free_thresh > nb_desc) {
> +		MACB_LOG(ERR, "tx_rs_thresh + tx_free_thresh must not "
> +			     "exceed nb_desc. (tx_rs_thresh=%u "
> +			     "tx_free_thresh=%u nb_desc=%u port = %d queue=%d)",
> +			     (unsigned int)tx_rs_thresh,
> +			     (unsigned int)tx_free_thresh,
> +			     (unsigned int)nb_desc,
> +			     (int)dev->data->port_id,
> +			     (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +	if (tx_rs_thresh >= (nb_desc - 2)) {
> +		MACB_LOG(ERR, "tx_rs_thresh must be less than the number "
> +			"of TX descriptors minus 2. (tx_rs_thresh=%u "
> +			"port=%d queue=%d)", (unsigned int)tx_rs_thresh,
> +			(int)dev->data->port_id, (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +	if (tx_rs_thresh > MACB_DEFAULT_TX_RS_THRESH) {
> +		MACB_LOG(ERR, "tx_rs_thresh must be less or equal than %u. "
> +			"(tx_rs_thresh=%u port=%d queue=%d)",
> +			MACB_DEFAULT_TX_RS_THRESH, (unsigned int)tx_rs_thresh,
> +			(int)dev->data->port_id, (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +	if (tx_free_thresh >= (nb_desc - 3)) {
> +		MACB_LOG(ERR, "tx_rs_thresh must be less than the "
> +			     "tx_free_thresh must be less than the number of "
> +			     "TX descriptors minus 3. (tx_free_thresh=%u "
> +			     "port=%d queue=%d)",
> +			     (unsigned int)tx_free_thresh,
> +			     (int)dev->data->port_id, (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +	if (tx_rs_thresh > tx_free_thresh) {
> +		MACB_LOG(ERR, "tx_rs_thresh must be less than or equal to "
> +			     "tx_free_thresh. (tx_free_thresh=%u "
> +			     "tx_rs_thresh=%u port=%d queue=%d)",
> +			     (unsigned int)tx_free_thresh,
> +			     (unsigned int)tx_rs_thresh,
> +			     (int)dev->data->port_id,
> +			     (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +	if ((nb_desc % tx_rs_thresh) != 0) {
> +		MACB_LOG(ERR, "tx_rs_thresh must be a divisor of the "
> +			     "number of TX descriptors. (tx_rs_thresh=%u "
> +			     "port=%d queue=%d)", (unsigned int)tx_rs_thresh,
> +			     (int)dev->data->port_id, (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +
> +	/*
> +	 * If rs_bit_thresh is greater than 1, then TX WTHRESH should be
> +	 * set to 0. If WTHRESH is greater than zero, the RS bit is ignored
> +	 * by the NIC and all descriptors are written back after the NIC
> +	 * accumulates WTHRESH descriptors.
> +	 */
> +	if (tx_rs_thresh > 1 && tx_conf->tx_thresh.wthresh != 0) {
> +		MACB_LOG(ERR, "TX WTHRESH must be set to 0 if "
> +			     "tx_rs_thresh is greater than 1. (tx_rs_thresh=%u "
> +			     "port=%d queue=%d)", (unsigned int)tx_rs_thresh,
> +			     (int)dev->data->port_id, (int)queue_idx);
> +		return -(EINVAL);
> +	}
> +
> +	/*
> +	 * Validate number of transmit descriptors.
> +	 * It must not exceed hardware maximum.
> +	 */
> +	if ((nb_desc % MACB_TX_LEN_ALIGN) != 0 || nb_desc > MACB_MAX_RING_DESC ||
> +		nb_desc < MACB_MIN_RING_DESC) {
> +		MACB_LOG(ERR, "number of descriptors exceeded.");
> +		return -EINVAL;
> +	}
> +
> +	bp->tx_ring_size = nb_desc;
> +
> +	/* Free memory prior to re-allocation if needed */
> +	if (dev->data->tx_queues[queue_idx] != NULL) {
> +		macb_tx_queue_release(dev->data->tx_queues[queue_idx]);
> +		dev->data->tx_queues[queue_idx] = NULL;
> +	}
> +
> +	/* First allocate the tx queue data structure */
> +	txq = rte_zmalloc("ethdev TX queue", sizeof(struct macb_tx_queue),
> +					  RTE_CACHE_LINE_SIZE);
> +	if (txq == NULL) {
> +		MACB_LOG(ERR, "failed to alloc txq.");
> +		return -ENOMEM;
> +	}
> +
> +	if (queue_idx) {
> +		txq->ISR = GEM_ISR(queue_idx - 1);
> +		txq->IER = GEM_IER(queue_idx - 1);
> +		txq->IDR = GEM_IDR(queue_idx - 1);
> +		txq->IMR = GEM_IMR(queue_idx - 1);
> +		txq->TBQP = GEM_TBQP(queue_idx - 1);
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			txq->TBQPH = GEM_TBQPH(queue_idx - 1);
> +	} else {
> +		/* queue0 uses legacy registers */
> +		txq->ISR = MACB_ISR;
> +		txq->IER = MACB_IER;
> +		txq->IDR = MACB_IDR;
> +		txq->IMR = MACB_IMR;
> +		txq->TBQP = MACB_TBQP;
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			txq->TBQPH = MACB_TBQPH;
> +	}
> +
> +	size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch;
> +
> +	tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx, size,
> +								  RTE_CACHE_LINE_SIZE, socket_id);
> +	if (tz == NULL) {
> +		macb_tx_queue_release(txq);
> +		MACB_LOG(ERR, "failed to alloc tx_ring.");
> +		return -ENOMEM;
> +	}
> +
> +	txq->bp = bp;
> +	txq->nb_tx_desc = nb_desc;
> +	txq->tx_rs_thresh = tx_rs_thresh;
> +	txq->tx_free_thresh = tx_free_thresh;
> +	txq->queue_id = queue_idx;
> +	txq->port_id = dev->data->port_id;
> +	txq->tx_ring_dma = tz->iova;
> +
> +	txq->tx_ring = (struct macb_dma_desc *)tz->addr;
> +	/* Allocate software ring */
> +	txq->tx_sw_ring =
> +		rte_zmalloc("txq->sw_ring", sizeof(struct macb_tx_entry) * nb_desc,
> +					RTE_CACHE_LINE_SIZE);
> +
> +	if (txq->tx_sw_ring == NULL) {
> +		macb_tx_queue_release(txq);
> +		MACB_LOG(ERR, "failed to alloc tx_sw_ring.");
> +		return -ENOMEM;
> +	}
> +
> +	macb_set_tx_function(txq, dev);
> +	macb_reset_tx_queue(txq, dev);
> +	dev->data->tx_queues[queue_idx] = txq;
> +
> +	return 0;
> +}
> +
> +int macb_tx_phyaddr_check(struct rte_eth_dev *dev)
> +{
> +	uint16_t i;
> +	uint32_t bus_addr_high;
> +	struct macb_tx_queue *txq;
> +
> +	if (dev->data->tx_queues == NULL) {
> +		MACB_LOG(ERR, "tx queue is null.");
> +		return -ENOMEM;
> +	}
> +	txq = dev->data->tx_queues[0];
> +	bus_addr_high = upper_32_bits(txq->tx_ring_dma);
> +
> +	/* Check the high address of the tx queue. */
> +	for (i = 1; i < dev->data->nb_tx_queues; i++) {
> +		txq = dev->data->tx_queues[i];
> +		if (bus_addr_high != upper_32_bits(txq->tx_ring_dma))
> +			return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +/*********************************************************************
> + *
> + *  Enable transmit unit.
> + *
> + **********************************************************************/
> +void __rte_cold macb_eth_tx_init(struct rte_eth_dev *dev)
> +{
> +	struct macb_tx_queue *txq;
> +	uint16_t i;
> +	struct macb_priv *priv;
> +	struct macb *bp;
> +
> +	priv = dev->data->dev_private;
> +	bp = priv->bp;
> +
> +	/* Setup the Base of the Tx Descriptor Rings. */
> +	for (i = 0; i < dev->data->nb_tx_queues; i++) {
> +		uint64_t bus_addr;
> +		txq = dev->data->tx_queues[i];
> +		bus_addr = txq->tx_ring_dma;
> +
> +		/* Disable tx interrupts */
> +		queue_writel(txq, IDR, -1);
> +		queue_readl(txq, ISR);
> +		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> +			queue_writel(txq, ISR, -1);
> +		queue_writel(txq, IDR, MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
> +
> +		queue_writel(txq, TBQP, lower_32_bits(bus_addr));
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			queue_writel(txq, TBQPH, upper_32_bits(bus_addr));
> +	}
> +
> +	/* Start tx queues */
> +	for (i = 0; i < dev->data->nb_tx_queues; i++)
> +		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
> +}
> +
> +void __rte_cold macb_rx_queue_release_mbufs_vec(struct macb_rx_queue *rxq)
> +{
> +	const unsigned int mask = rxq->nb_rx_desc - 1;
> +	unsigned int i;
> +
> +	if (rxq->rx_sw_ring == NULL || rxq->rxrearm_nb >= rxq->nb_rx_desc)
> +		return;
> +
> +	/* free all mbufs that are valid in the ring */
> +	if (rxq->rxrearm_nb == 0) {
> +		for (i = 0; i < rxq->nb_rx_desc; i++) {
> +			if (rxq->rx_sw_ring[i].mbuf != NULL)
> +				rte_pktmbuf_free_seg(rxq->rx_sw_ring[i].mbuf);
> +		}
> +	} else {
> +		for (i = rxq->rx_tail;
> +		     i != rxq->rxrearm_start;
> +		     i = (i + 1) & mask) {
> +			if (rxq->rx_sw_ring[i].mbuf != NULL)
> +				rte_pktmbuf_free_seg(rxq->rx_sw_ring[i].mbuf);
> +		}
> +	}
> +
> +	rxq->rxrearm_nb = rxq->nb_rx_desc;
> +
> +	/* set all entries to NULL */
> +	memset(rxq->rx_sw_ring, 0, sizeof(rxq->rx_sw_ring[0]) * rxq->nb_rx_desc);
> +}
> +
> +void __rte_cold macb_rx_queue_release_mbufs(struct macb_rx_queue *rxq)
> +{
> +	unsigned int i;
> +	struct macb *bp = rxq->bp;
> +
> +	if (rxq->pkt_first_seg != NULL) {
> +		rte_pktmbuf_free(rxq->pkt_first_seg);
> +		rxq->pkt_first_seg = NULL;
> +	}
> +
> +	if (bp->rx_vec_allowed) {
> +		macb_rx_queue_release_mbufs_vec(rxq);
> +		return;
> +	}
> +
> +	if (rxq->rx_sw_ring != NULL) {
> +		for (i = 0; i < rxq->nb_rx_desc; i++) {
> +			if (rxq->rx_sw_ring[i].mbuf != NULL) {
> +				rte_pktmbuf_free_seg(rxq->rx_sw_ring[i].mbuf);
> +				rxq->rx_sw_ring[i].mbuf = NULL;
> +			}
> +		}
> +	}
> +}
> +
> +static void __rte_cold macb_rx_queue_release(struct macb_rx_queue *rxq)
> +{
> +	if (rxq != NULL) {
> +		macb_rx_queue_release_mbufs(rxq);
> +		rte_free(rxq->rx_sw_ring);
> +		rte_free(rxq);
> +	}
> +}
> +
> +void __rte_cold macb_eth_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
> +{
> +	macb_rx_queue_release(dev->data->rx_queues[qid]);
> +}
> +
> +void __rte_cold macb_dev_free_queues(struct rte_eth_dev *dev)
> +{
> +	uint16_t i;
> +
> +	for (i = 0; i < dev->data->nb_rx_queues; i++) {
> +		macb_eth_rx_queue_release(dev, i);
> +		dev->data->rx_queues[i] = NULL;
> +		rte_eth_dma_zone_free(dev, "rx_ring", i);
> +	}
> +
> +	dev->data->nb_rx_queues = 0;
> +
> +	for (i = 0; i < dev->data->nb_tx_queues; i++) {
> +		macb_eth_tx_queue_release(dev, i);
> +		dev->data->tx_queues[i] = NULL;
> +		rte_eth_dma_zone_free(dev, "tx_ring", i);
> +	}
> +	dev->data->nb_tx_queues = 0;
> +}
> +
> +void __rte_cold macb_reset_rx_queue(struct macb_rx_queue *rxq)
> +{
> +	unsigned int i;
> +	struct macb_dma_desc *rxdesc;
> +
> +	uint16_t len = rxq->nb_rx_desc;
> +
> +	if (rxq->bp->rx_bulk_alloc_allowed)
> +		len += MACB_MAX_RX_BURST;
> +
> +	/* Zero out HW ring memory */
> +	for (i = 0; i < rxq->nb_rx_desc; i++) {
> +		rxdesc = macb_rx_desc(rxq, i);
> +		rxdesc->ctrl = 0;
> +		macb_set_addr(rxq->bp, rxdesc, 0);
> +	}
> +
> +	if (rxq->bp->rx_bulk_alloc_allowed) {
> +		rxdesc = macb_rx_desc(rxq, rxq->nb_rx_desc - 1);
> +
> +		for (i = 0; i < MACB_MAX_RX_BURST; i++) {
> +			rxdesc += MACB_DESC_ADDR_INTERVAL;
> +			rxdesc->ctrl = 0;
> +			macb_set_addr(rxq->bp, rxdesc, 0);
> +		}
> +	}
> +
> +	/*
> +	 * initialize extra software ring entries. Space for these extra
> +	 * entries is always allocated
> +	 */
> +	memset(&rxq->fake_mbuf, 0x0, sizeof(rxq->fake_mbuf));
> +	for (i = rxq->nb_rx_desc; i < len; ++i) {
> +		if (rxq->rx_sw_ring[i].mbuf == NULL)
> +			rxq->rx_sw_ring[i].mbuf = &rxq->fake_mbuf;
> +	}
> +
> +	rxq->rx_tail = 0;
> +	rxq->pkt_first_seg = NULL;
> +	rxq->pkt_last_seg = NULL;
> +
> +	rxq->rxrearm_start = 0;
> +	rxq->rxrearm_nb = 0;
> +}
> +
> +uint64_t __rte_cold macb_get_rx_port_offloads_capa(struct rte_eth_dev *dev __rte_unused)
> +{
> +	uint64_t rx_offload_capa;
> +
> +	rx_offload_capa = RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
> +			  RTE_ETH_RX_OFFLOAD_TCP_CKSUM | RTE_ETH_RX_OFFLOAD_SCATTER |
> +			  RTE_ETH_RX_OFFLOAD_KEEP_CRC;
> +
> +	return rx_offload_capa;
> +}
> +
> +uint64_t __rte_cold macb_get_rx_queue_offloads_capa(struct rte_eth_dev *dev)
> +{
> +	uint64_t rx_queue_offload_capa;
> +
> +	/*
> +	 * As only one Rx queue can be used, let per queue offloading
> +	 * capability be same to per port queue offloading capability
> +	 * for better convenience.
> +	 */
> +	rx_queue_offload_capa = macb_get_rx_port_offloads_capa(dev);
> +
> +	return rx_queue_offload_capa;
> +}
> +
> +/*
> + * Check if Rx Burst Bulk Alloc function can be used.
> + * Return
> + *        0: the preconditions are satisfied and the bulk allocation function
> + *           can be used.
> + *  -EINVAL: the preconditions are NOT satisfied and the default Rx burst
> + *           function must be used.
> + */
> +static inline int __rte_cold
> +macb_rx_burst_bulk_alloc_preconditions(struct macb_rx_queue *rxq)
> +{
> +	int ret = 0;
> +
> +	/*
> +	 * Make sure the following pre-conditions are satisfied:
> +	 *   rxq->rx_free_thresh >= MACB_MAX_RX_BURST
> +	 *   rxq->rx_free_thresh < rxq->nb_rx_desc
> +	 *   (rxq->nb_rx_desc % rxq->rx_free_thresh) == 0
> +	 */
> +	if (!(rxq->rx_free_thresh >= MACB_MAX_RX_BURST)) {
> +		MACB_INFO("Rx Burst Bulk Alloc Preconditions: "
> +				"rxq->rx_free_thresh=%d, "
> +				"MACB_MAX_RX_BURST=%d",
> +				rxq->rx_free_thresh, MACB_MAX_RX_BURST);
> +		ret = -EINVAL;
> +	} else if (!(rxq->rx_free_thresh < rxq->nb_rx_desc)) {
> +		MACB_INFO("Rx Burst Bulk Alloc Preconditions: "
> +				"rxq->rx_free_thresh=%d, "
> +				"rxq->nb_rx_desc=%d",
> +				rxq->rx_free_thresh, rxq->nb_rx_desc);
> +		ret = -EINVAL;
> +	} else if (!((rxq->nb_rx_desc % rxq->rx_free_thresh) == 0)) {
> +		MACB_INFO("Rx Burst Bulk Alloc Preconditions: "
> +				"rxq->nb_rx_desc=%d, "
> +				"rxq->rx_free_thresh=%d",
> +				rxq->nb_rx_desc, rxq->rx_free_thresh);
> +		ret = -EINVAL;
> +	}
> +	return ret;
> +}
> +
> +int __rte_cold macb_eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
> +							uint16_t nb_desc, unsigned int socket_id,
> +							const struct rte_eth_rxconf *rx_conf,
> +							struct rte_mempool *mp)
> +{
> +	const struct rte_memzone *rz;
> +	struct macb_rx_queue *rxq;
> +	unsigned int size;
> +	struct macb_priv *priv;
> +	struct macb *bp;
> +	uint64_t offloads;
> +	uint16_t len = nb_desc;
> +
> +	offloads = rx_conf->offloads | dev->data->dev_conf.rxmode.offloads;
> +
> +	priv = dev->data->dev_private;
> +	bp = priv->bp;
> +
> +	/*
> +	 * Validate number of receive descriptors.
> +	 * It must not exceed hardware maximum, and must be multiple
> +	 * of MACB_RX_LEN_ALIGN.
> +	 */
> +	if (nb_desc % MACB_RX_LEN_ALIGN != 0 || nb_desc > MACB_MAX_RING_DESC ||
> +		nb_desc < MACB_MIN_RING_DESC) {
> +		return -EINVAL;
> +	}
> +
> +	bp->rx_ring_size = nb_desc;
> +
> +	/* Free memory prior to re-allocation if needed */
> +	if (dev->data->rx_queues[queue_idx] != NULL) {
> +		macb_rx_queue_release(dev->data->rx_queues[queue_idx]);
> +		dev->data->rx_queues[queue_idx] = NULL;
> +	}
> +
> +	/* First allocate the RX queue data structure. */
> +	rxq = rte_zmalloc("ethdev RX queue", sizeof(struct macb_rx_queue),
> +					  RTE_CACHE_LINE_SIZE);
> +	if (rxq == NULL) {
> +		MACB_LOG(ERR, "failed to alloc rxq.");
> +		return -ENOMEM;
> +	}
> +
> +	if (queue_idx) {
> +		rxq->ISR = GEM_ISR(queue_idx - 1);
> +		rxq->IER = GEM_IER(queue_idx - 1);
> +		rxq->IDR = GEM_IDR(queue_idx - 1);
> +		rxq->IMR = GEM_IMR(queue_idx - 1);
> +		rxq->RBQP = GEM_RBQP(queue_idx - 1);
> +		rxq->RBQS = GEM_RBQS(queue_idx - 1);
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			rxq->RBQPH = GEM_RBQPH(queue_idx - 1);
> +	} else {
> +		/* queue0 uses legacy registers */
> +		rxq->ISR = MACB_ISR;
> +		rxq->IER = MACB_IER;
> +		rxq->IDR = MACB_IDR;
> +		rxq->IMR = MACB_IMR;
> +		rxq->RBQP = MACB_RBQP;
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			rxq->RBQPH = MACB_RBQPH;
> +	}
> +
> +	rxq->bp = bp;
> +	rxq->offloads = offloads;
> +	rxq->mb_pool = mp;
> +	rxq->nb_rx_desc = nb_desc;
> +	rxq->rx_free_thresh = rx_conf->rx_free_thresh;
> +	rxq->queue_id = queue_idx;
> +	rxq->port_id = dev->data->port_id;
> +	if (dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC)
> +		rxq->crc_len = RTE_ETHER_CRC_LEN;
> +	else
> +		rxq->crc_len = 0;
> +
> +	/*
> +	 * Certain constraints must be met in order to use the bulk buffer
> +	 * allocation Rx burst function. If any of Rx queues doesn't meet them
> +	 * the feature should be disabled for the whole port.
> +	 */
> +	if (macb_rx_burst_bulk_alloc_preconditions(rxq)) {
> +		MACB_INFO("queue[%d] doesn't meet Rx Bulk Alloc "
> +				    "preconditions - canceling the feature for "
> +				    "port[%d]",
> +			     rxq->queue_id, rxq->port_id);
> +		bp->rx_bulk_alloc_allowed = false;
> +	}
> +
> +	/*
> +	 *  Allocate RX ring hardware descriptors. A memzone large enough to
> +	 *  handle the maximum ring size is allocated in order to allow for
> +	 *  resizing in later calls to the queue setup function.
> +	 */
> +	size = RX_RING_BYTES(bp) + bp->rx_bd_rd_prefetch;
> +
> +	if (rxq->bp->rx_bulk_alloc_allowed)
> +		size += macb_dma_desc_get_size(bp) * MACB_MAX_RX_BURST;
> +
> +	rz = rte_eth_dma_zone_reserve(dev, "rx_ring", queue_idx, size,
> +								  RTE_CACHE_LINE_SIZE, socket_id);
> +
> +	if (rz == NULL) {
> +		macb_rx_queue_release(rxq);
> +		MACB_LOG(ERR, "failed to alloc rx_ring.");
> +		return -ENOMEM;
> +	}
> +
> +	rxq->rx_ring_dma = rz->iova;
> +	rxq->rx_ring = (struct macb_dma_desc *)rz->addr;
> +
> +	if (rxq->bp->rx_bulk_alloc_allowed)
> +		len += MACB_MAX_RX_BURST;
> +
> +	/* Allocate software ring. */
> +	rxq->rx_sw_ring =
> +		rte_zmalloc("rxq->sw_ring", sizeof(struct macb_rx_entry) * len,
> +					RTE_CACHE_LINE_SIZE);
> +	if (rxq->rx_sw_ring == NULL) {
> +		macb_rx_queue_release(rxq);
> +		MACB_LOG(ERR, "failed to alloc rx_sw_ring.");
> +		return -ENOMEM;
> +	}
> +	/* MACB_LOG(DEBUG, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
> +	 * rxq->rx_sw_ring, rxq->rx_ring, rxq->rx_ring_dma);
> +	 */
> +
> +	dev->data->rx_queues[queue_idx] = rxq;
> +	macb_reset_rx_queue(rxq);
> +
> +	return 0;
> +}
> +
> +void __rte_cold macb_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
> +					   struct rte_eth_rxq_info *qinfo)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	struct macb_rx_queue *rxq;
> +
> +	rxq = dev->data->rx_queues[queue_id];
> +
> +	qinfo->mp = rxq->mb_pool;
> +	qinfo->scattered_rx = dev->data->scattered_rx;
> +	qinfo->rx_buf_size = bp->rx_buffer_size;
> +	qinfo->nb_desc = rxq->nb_rx_desc;
> +	qinfo->conf.rx_free_thresh = rxq->rx_free_thresh;
> +	qinfo->conf.offloads = rxq->offloads;
> +}
> +
> +void __rte_cold macb_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
> +					   struct rte_eth_txq_info *qinfo)
> +{
> +	struct macb_tx_queue *txq;
> +
> +	txq = dev->data->tx_queues[queue_id];
> +	qinfo->nb_desc = txq->nb_tx_desc;
> +	qinfo->conf.tx_free_thresh = txq->tx_free_thresh;
> +}
> +
> +static int __rte_cold macb_alloc_rx_queue_mbufs(struct macb_rx_queue *rxq)
> +{
> +	struct macb_rx_entry *rxe = rxq->rx_sw_ring;
> +	uint64_t dma_addr;
> +	unsigned int i;
> +	struct macb *bp;
> +
> +	bp = rxq->bp;
> +
> +	/* Initialize software ring entries. */
> +	for (i = 0; i < rxq->nb_rx_desc; i++) {
> +		struct macb_dma_desc *rxd;
> +		struct rte_mbuf *mbuf = rte_mbuf_raw_alloc(rxq->mb_pool);
> +
> +		if (mbuf == NULL) {
> +			MACB_LOG(ERR, "RX mbuf alloc failed "
> +				     "queue_id=%hu", rxq->queue_id);

1. If this fails on (i != 0), what happens to mbufs [0, i - 1]? Leak?
2. Why not allocate a bulk of mbufs right before the loop?

Thank you.

> +			return -ENOMEM;
> +		}
> +		mbuf->data_off = RTE_PKTMBUF_HEADROOM + MACB_RX_DATA_OFFSET;
> +		dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(mbuf));
> +		rxd = macb_rx_desc(rxq, i);
> +		if (i == rxq->nb_rx_desc - 1)
> +			dma_addr |= MACB_BIT(RX_WRAP);
> +		rxd->ctrl = 0;
> +		/* Setting addr clears RX_USED and allows reception,
> +		 * make sure ctrl is cleared first to avoid a race.
> +		 */
> +		rte_wmb();
> +		macb_set_addr(bp, rxd, dma_addr);
> +		rxe[i].mbuf = mbuf;
> +	}
> +
> +	rte_wmb();
> +	return 0;
> +}
> +
> +void __rte_cold macb_init_rx_buffer_size(struct macb *bp, size_t size)
> +{
> +	if (!macb_is_gem(bp)) {
> +		bp->rx_buffer_size = MACB_RX_BUFFER_SIZE;
> +	} else {
> +		bp->rx_buffer_size = size;
> +
> +		if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) {
> +			bp->rx_buffer_size =
> +				roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE);
> +		}
> +	}
> +}
> +
> +static void __rte_cold
> +macb_set_rx_function(struct macb_rx_queue *rxq, struct rte_eth_dev *dev)
> +{
> +	struct macb_priv *priv = dev->data->dev_private;
> +	struct macb *bp = priv->bp;
> +	u32	max_len;
> +	uint16_t buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) -
> +							RTE_PKTMBUF_HEADROOM);
> +
> +	max_len = dev->data->mtu + MACB_ETH_OVERHEAD;
> +	if (max_len > buf_size ||
> +	    dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER) {
> +		if (!dev->data->scattered_rx)
> +			MACB_INFO("forcing scatter mode");
> +		dev->data->scattered_rx = 1;
> +	}
> +
> +	/*
> +	 * In order to allow Vector Rx there are a few configuration
> +	 * conditions to be met and Rx Bulk Allocation should be allowed.
> +	 */
> +	if (!bp->rx_bulk_alloc_allowed ||
> +			rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_128) {
> +		MACB_INFO("Port[%d] doesn't meet Vector Rx "
> +				    "preconditions",
> +			     dev->data->port_id);
> +		bp->rx_vec_allowed = false;
> +	}
> +
> +	if (dev->data->scattered_rx) {
> +		if (bp->rx_vec_allowed) {
> +			MACB_INFO("Using Vector Scattered Rx "
> +						"callback (port=%d).",
> +						dev->data->port_id);
> +			dev->rx_pkt_burst = macb_eth_recv_scattered_pkts_vec;
> +		} else {
> +			MACB_INFO("Using Regular (non-vector) "
> +					    "Scattered Rx callback "
> +					    "(port=%d).",
> +				     dev->data->port_id);
> +			dev->rx_pkt_burst = macb_eth_recv_scattered_pkts;
> +		}
> +	} else {
> +		if (bp->rx_vec_allowed) {
> +			MACB_INFO("Vector rx enabled");
> +			dev->rx_pkt_burst = macb_eth_recv_pkts_vec;
> +		} else {
> +			dev->rx_pkt_burst = macb_eth_recv_pkts;
> +		}
> +	}
> +}
> +
> +int macb_rx_phyaddr_check(struct rte_eth_dev *dev)
> +{
> +	uint16_t i;
> +	uint32_t bus_addr_high;
> +	struct macb_rx_queue *rxq;
> +
> +	if (dev->data->rx_queues == NULL) {
> +		MACB_LOG(ERR, "rx queue is null.");
> +		return -ENOMEM;
> +	}
> +	rxq = dev->data->rx_queues[0];
> +	bus_addr_high = upper_32_bits(rxq->rx_ring_dma);
> +
> +	/* Check the high address of the rx queue. */
> +	for (i = 1; i < dev->data->nb_rx_queues; i++) {
> +		rxq = dev->data->rx_queues[i];
> +		if (bus_addr_high != upper_32_bits(rxq->rx_ring_dma))
> +			return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +int __rte_cold macb_eth_rx_init(struct rte_eth_dev *dev)
> +{
> +	int ret;
> +	uint16_t i;
> +	uint32_t rxcsum;
> +	struct macb_rx_queue *rxq;
> +	struct rte_eth_rxmode *rxmode;
> +
> +	struct macb_priv *priv;
> +	struct macb *bp;
> +	uint16_t buf_size;
> +
> +	priv = dev->data->dev_private;
> +	bp = priv->bp;
> +
> +	rxcsum = gem_readl(bp, NCFGR);
> +	/* Enable both L3/L4 rx checksum offload */
> +	rxmode = &dev->data->dev_conf.rxmode;
> +	if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM)
> +		rxcsum |= GEM_BIT(RXCOEN);
> +	else
> +		rxcsum &= ~GEM_BIT(RXCOEN);
> +	gem_writel(bp, NCFGR, rxcsum);
> +
> +	/* Configure and enable each RX queue. */
> +	for (i = 0; i < dev->data->nb_rx_queues; i++) {
> +		uint64_t bus_addr;
> +
> +		rxq = dev->data->rx_queues[i];
> +		rxq->flags = 0;
> +
> +		/* Disable rx interrupts */
> +		queue_writel(rxq, IDR, -1);
> +		queue_readl(rxq, ISR);
> +		if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> +			queue_writel(rxq, ISR, -1);
> +		queue_writel(rxq, IDR, MACB_RX_INT_FLAGS | MACB_BIT(HRESP));
> +
> +		/* Allocate buffers for descriptor rings and set up queue */
> +		ret = macb_alloc_rx_queue_mbufs(rxq);
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * Reset crc_len in case it was changed after queue setup by a
> +		 *  call to configure
> +		 */
> +		if (dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC)
> +			rxq->crc_len = RTE_ETHER_CRC_LEN;
> +		else
> +			rxq->crc_len = 0;
> +
> +		bus_addr = rxq->rx_ring_dma;
> +		queue_writel(rxq, RBQP, lower_32_bits(bus_addr));
> +		if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +			queue_writel(rxq, RBQPH, upper_32_bits(bus_addr));
> +
> +		/*
> +		 * Configure RX buffer size.
> +		 */
> +		buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) -
> +							  RTE_PKTMBUF_HEADROOM);
> +
> +		macb_init_rx_buffer_size(bp, buf_size);
> +		macb_set_rx_function(rxq, dev);
> +	}
> +
> +	/* Start rx queues */
> +	for (i = 0; i < dev->data->nb_rx_queues; i++)
> +		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
> +
> +	return 0;
> +}
> +
> +uint16_t
> +macb_eth_recv_pkts_vec(void *rx_queue __rte_unused,
> +		       struct rte_mbuf **rx_pkts __rte_unused,
> +		       uint16_t nb_pkts __rte_unused)
> +{
> +	return 0;
> +}
> +
> +uint16_t
> +macb_eth_recv_scattered_pkts_vec(void *rx_queue __rte_unused,
> +				  struct rte_mbuf **rx_pkts __rte_unused,
> +				  uint16_t nb_pkts __rte_unused)
> +{
> +	return 0;
> +}
> +
> +uint16_t
> +macb_eth_xmit_pkts_vec(void *tx_queue __rte_unused,
> +				struct rte_mbuf **tx_pkts __rte_unused,
> +				uint16_t nb_pkts __rte_unused)
> +{
> +	return 0;
> +}
> diff --git a/drivers/net/macb/macb_rxtx.h b/drivers/net/macb/macb_rxtx.h
> new file mode 100644
> index 0000000..6b0b45a
> --- /dev/null
> +++ b/drivers/net/macb/macb_rxtx.h
> @@ -0,0 +1,325 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 Phytium Technology Co., Ltd.
> + */
> +
> +#ifndef _MACB_RXTX_H_
> +#define _MACB_RXTX_H_
> +
> +#include "macb_ethdev.h"
> +
> +#define MACB_RX_BUFFER_SIZE 128
> +#define MACB_MAX_RECLAIM_NUM 64
> +#define MACB_RX_DATA_OFFSET   0
> +
> +#define MACB_DESCS_PER_LOOP    4
> +#define MACB_MAX_RX_BURST    32
> +#define MACB_RXQ_REARM_THRESH      32
> +#define MACB_DESC_ADDR_INTERVAL 2
> +#define MACB_LOOK_AHEAD	8
> +#define MACB_NEXT_FETCH	7
> +#define MACB_NEON_PREFETCH_ENTRY	4
> +
> +#define BIT_TO_BYTE_SHIFT 3
> +#define MACB_DATA_BUS_WIDTH_MASK(x) (((x) >> BIT_TO_BYTE_SHIFT) - 1)
> +
> +struct gem_tx_ts {
> +	struct rte_mbuf *mbuf;
> +	struct macb_dma_desc_ptp desc_ptp;
> +};
> +
> +struct __rte_cache_aligned macb_rx_queue_stats {
> +	union {
> +		uint64_t first;
> +		uint64_t rx_packets;
> +	};
> +	uint64_t rx_bytes;
> +	uint64_t rx_dropped;
> +};
> +
> +struct __rte_cache_aligned macb_tx_queue_stats {
> +	uint64_t tx_packets;
> +	uint64_t tx_bytes;
> +	uint64_t tx_dropped;
> +	uint64_t tx_start_packets;
> +	uint64_t tx_start_bytes;
> +};
> +
> +struct macb_tx_entry {
> +	struct rte_mbuf *mbuf;
> +};
> +
> +struct macb_rx_entry {
> +	struct rte_mbuf *mbuf;
> +};
> +
> +struct macb_rx_queue {
> +	struct macb		*bp;
> +	struct rte_mempool	*mb_pool;   /**< mbuf pool to populate RX ring. */
> +
> +	unsigned int		ISR;
> +	unsigned int		IER;
> +	unsigned int		IDR;
> +	unsigned int		IMR;
> +	unsigned int		RBQS;
> +	unsigned int		RBQP;
> +	unsigned int		RBQPH;
> +
> +	rte_iova_t		rx_ring_dma;
> +	unsigned int		rx_tail;
> +	unsigned int		nb_rx_desc;    /**< number of TX descriptors. */
> +	uint16_t		rx_free_thresh;/**< max free RX desc to hold. */
> +	uint16_t		queue_id; /**< TX queue index. */
> +	uint16_t		port_id;  /**< Device port identifier. */
> +	uint32_t		crc_len;    /**< 0 if CRC stripped, 4 otherwise. */
> +	uint32_t		flags;      /**< RX flags. */
> +	uint64_t		offloads;   /**< offloads of DEV_RX_OFFLOAD_* */
> +	unsigned int		rx_prepared_head;
> +	struct macb_dma_desc	*rx_ring;
> +	struct macb_rx_entry	*rx_sw_ring;
> +
> +	struct macb_rx_queue_stats	stats;
> +	struct rte_mbuf		*pkt_first_seg; /**< First segment of current packet. */
> +	struct rte_mbuf		*pkt_last_seg;  /**< Last segment of current packet. */
> +
> +	uint16_t		rxrearm_nb;     /**< number of remaining to be re-armed */
> +	unsigned int		rxrearm_start;  /**< the idx we start the re-arming from */
> +
> +	/** need to alloc dummy mbuf, for wraparound when scanning hw ring */
> +	struct rte_mbuf		fake_mbuf;
> +};
> +
> +struct macb_tx_queue {
> +	struct macb		*bp;
> +
> +	unsigned int		ISR;
> +	unsigned int		IER;
> +	unsigned int		IDR;
> +	unsigned int		IMR;
> +	unsigned int		TBQP;
> +	unsigned int		TBQPH;
> +
> +	unsigned int		tx_head, tx_tail;
> +	unsigned int		nb_tx_desc;    /**< number of TX descriptors. */
> +	uint16_t		tx_free_thresh;/**< max free TX desc to hold. */
> +	uint16_t		tx_rs_thresh;
> +	uint16_t		queue_id; /**< TX queue index. */
> +	uint16_t		port_id;  /**< Device port identifier. */
> +
> +	struct macb_dma_desc	*tx_ring;
> +	struct macb_tx_entry	*tx_sw_ring;
> +	rte_iova_t		tx_ring_dma;
> +
> +	struct macb_tx_queue_stats	stats;
> +};
> +
> +void macb_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
> +		       struct rte_eth_rxq_info *qinfo);
> +void macb_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
> +		       struct rte_eth_txq_info *qinfo);
> +uint64_t macb_get_rx_port_offloads_capa(struct rte_eth_dev *dev);
> +uint64_t macb_get_rx_queue_offloads_capa(struct rte_eth_dev *dev);
> +int macb_eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
> +			    unsigned int socket, const struct rte_eth_rxconf *conf __rte_unused,
> +			    struct rte_mempool *mp);
> +int macb_eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
> +			    unsigned int socket, const struct rte_eth_txconf *conf);
> +void macb_eth_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
> +void macb_eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
> +void macb_dev_free_queues(struct rte_eth_dev *dev);
> +uint16_t macb_eth_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
> +uint16_t macb_eth_xmit_pkts_vec(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
> +uint16_t macb_eth_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
> +uint16_t macb_eth_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
> +uint16_t macb_eth_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
> +uint16_t macb_eth_recv_scattered_pkts_vec(void *rx_queue,
> +					  struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
> +uint16_t eth_macb_prep_pkts(__rte_unused void *tx_queue,
> +			    struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
> +void __rte_cold macb_rx_queue_release_mbufs_vec(struct macb_rx_queue *rxq);
> +void macb_rx_queue_release_mbufs(struct macb_rx_queue *rxq);
> +void macb_tx_queue_release_mbufs(struct macb_tx_queue *txq);
> +int macb_rx_phyaddr_check(struct rte_eth_dev *dev);
> +int macb_tx_phyaddr_check(struct rte_eth_dev *dev);
> +int macb_eth_rx_init(struct rte_eth_dev *dev);
> +void macb_eth_tx_init(struct rte_eth_dev *dev);
> +void macb_reset_rx_queue(struct macb_rx_queue *rxq);
> +void macb_reset_tx_queue(struct macb_tx_queue *txq, struct rte_eth_dev *dev);
> +void macb_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, struct rte_eth_rxq_info *qinfo);
> +void macb_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, struct rte_eth_txq_info *qinfo);
> +
> +void macb_init_rx_buffer_size(struct macb *bp, size_t size);
> +
> +
> +/* DMA buffer descriptor might be different size
> + * depends on hardware configuration:
> + *
> + * 1. dma address width 32 bits:
> + *    word 1: 32 bit address of Data Buffer
> + *    word 2: control
> + *
> + * 2. dma address width 64 bits:
> + *    word 1: 32 bit address of Data Buffer
> + *    word 2: control
> + *    word 3: upper 32 bit address of Data Buffer
> + *    word 4: unused
> + *
> + * 3. dma address width 32 bits with hardware timestamping:
> + *    word 1: 32 bit address of Data Buffer
> + *    word 2: control
> + *    word 3: timestamp word 1
> + *    word 4: timestamp word 2
> + *
> + * 4. dma address width 64 bits with hardware timestamping:
> + *    word 1: 32 bit address of Data Buffer
> + *    word 2: control
> + *    word 3: upper 32 bit address of Data Buffer
> + *    word 4: unused
> + *    word 5: timestamp word 1
> + *    word 6: timestamp word 2
> + */
> +static inline unsigned int macb_dma_desc_get_size(struct macb *bp)
> +{
> +	unsigned int desc_size;
> +
> +	switch (bp->hw_dma_cap) {
> +	case HW_DMA_CAP_64B:
> +		desc_size =
> +			sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64);
> +		break;
> +	case HW_DMA_CAP_PTP:
> +		desc_size =
> +			sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_ptp);
> +		break;
> +	case HW_DMA_CAP_64B_PTP:
> +		desc_size = sizeof(struct macb_dma_desc) +
> +					sizeof(struct macb_dma_desc_64) +
> +					sizeof(struct macb_dma_desc_ptp);
> +		break;
> +	default:
> +		desc_size = sizeof(struct macb_dma_desc);
> +	}
> +	return desc_size;
> +
> +	return sizeof(struct macb_dma_desc);
> +}
> +
> +/* Ring buffer accessors */
> +static inline unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
> +{
> +	return index & (bp->tx_ring_size - 1);
> +}
> +
> +static inline unsigned int macb_adj_dma_desc_idx(struct macb *bp,
> +						unsigned int desc_idx)
> +{
> +#ifdef MACB_EXT_DESC
> +	switch (bp->hw_dma_cap) {
> +	case HW_DMA_CAP_64B:
> +	case HW_DMA_CAP_PTP:
> +		desc_idx <<= 1;
> +		break;
> +	case HW_DMA_CAP_64B_PTP:
> +		desc_idx *= 3;
> +		break;
> +	default:
> +		break;
> +	}
> +#endif
> +	return desc_idx;
> +}
> +
> +static inline struct macb_tx_entry *macb_tx_entry(struct macb_tx_queue *queue,
> +						unsigned int index)
> +{
> +	return &queue->tx_sw_ring[macb_tx_ring_wrap(queue->bp, index)];
> +}
> +
> +static inline struct macb_dma_desc *macb_tx_desc(struct macb_tx_queue *queue,
> +						 unsigned int index)
> +{
> +	index = macb_tx_ring_wrap(queue->bp, index);
> +	index = macb_adj_dma_desc_idx(queue->bp, index);
> +	return &queue->tx_ring[index];
> +}
> +
> +static inline struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp,
> +						 struct macb_dma_desc *desc)
> +{
> +	if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> +		return (struct macb_dma_desc_64 *)((uint8_t *)desc
> +						   + sizeof(struct macb_dma_desc));
> +	return NULL;
> +}
> +
> +static inline void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc,
> +							dma_addr_t addr)
> +{
> +	struct macb_dma_desc_64 *desc_64;
> +
> +	if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
> +		desc_64 = macb_64b_desc(bp, desc);
> +		desc_64->addrh = upper_32_bits(addr);
> +		/* The low bits of RX address contain the RX_USED bit, clearing
> +		 * of which allows packet RX. Make sure the high bits are also
> +		 * visible to HW at that point.
> +		 */
> +		rte_wmb();
> +	}
> +
> +	desc->addr = lower_32_bits(addr);
> +}
> +
> +static inline unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index)
> +{
> +	return index & (bp->rx_ring_size - 1);
> +}
> +
> +static inline struct macb_dma_desc *macb_rx_desc(struct macb_rx_queue *queue,
> +						unsigned int index)
> +{
> +	index = macb_rx_ring_wrap(queue->bp, index);
> +	index = macb_adj_dma_desc_idx(queue->bp, index);
> +	return &queue->rx_ring[index];
> +}
> +
> +static inline struct macb_rx_entry *macb_rx_entry(struct macb_rx_queue *queue,
> +						unsigned int index)
> +{
> +	return &queue->rx_sw_ring[macb_rx_ring_wrap(queue->bp, index)];
> +}
> +
> +static inline uint16_t macb_reclaim_txd(struct macb_tx_queue *queue)
> +{
> +	struct macb_dma_desc *curr_desc;
> +	uint32_t tx_head, tx_tail;
> +	uint16_t reclaim = 0;
> +
> +	tx_head = queue->tx_head;
> +	tx_tail = queue->tx_tail;
> +	while (likely(tx_head != tx_tail && reclaim < MACB_MAX_RECLAIM_NUM)) {
> +		curr_desc = macb_tx_desc(queue, tx_head);
> +		if (unlikely(!(curr_desc->ctrl & MACB_BIT(TX_USED)))) {
> +			goto out;
> +		} else {
> +			if (likely(curr_desc->ctrl & MACB_BIT(TX_LAST))) {
> +				tx_head = macb_tx_ring_wrap(queue->bp, ++tx_head);
> +				reclaim++;
> +			} else {
> +				reclaim++;
> +				do {
> +					tx_head = macb_tx_ring_wrap(queue->bp, ++tx_head);
> +					curr_desc = macb_tx_desc(queue, tx_head);
> +					curr_desc->ctrl |= MACB_BIT(TX_USED);
> +					reclaim++;
> +				} while (unlikely(!(curr_desc->ctrl & MACB_BIT(TX_LAST))));
> +				tx_head = macb_tx_ring_wrap(queue->bp, ++tx_head);
> +			}
> +		}
> +	}
> +
> +out:
> +	queue->tx_head = tx_head;
> +	return reclaim;
> +}
> +
> +#endif /* _MACB_RXTX_H_ */
> diff --git a/drivers/net/macb/meson.build b/drivers/net/macb/meson.build
> new file mode 100644
> index 0000000..fe0dc99
> --- /dev/null
> +++ b/drivers/net/macb/meson.build
> @@ -0,0 +1,18 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2022 Phytium Technology Co., Ltd.
> +
> +if not is_linux
> +    build = false
> +    reason = 'only supported on Linux'
> +    subdir_done()
> +endif
> +
> +subdir('base')
> +objs = [base_objs]
> +
> +sources = files(
> +        'macb_ethdev.c',
> +        'macb_rxtx.c',
> +)
> +
> +includes += include_directories('base')
> diff --git a/drivers/net/meson.build b/drivers/net/meson.build
> index 61f8cdd..28e160c 100644
> --- a/drivers/net/meson.build
> +++ b/drivers/net/meson.build
> @@ -34,6 +34,7 @@ drivers = [
>         'intel/ixgbe',
>         'intel/cpfl',  # depends on idpf, so must come after it
>         'ionic',
> +        'macb',
>         'mana',
>         'memif',
>         'mlx4',
> -- 
> 2.7.4
>
>


More information about the dev mailing list