From: liwencheng <liwencheng@phytium.com.cn>
To: liwencheng@phytium.com.cn
Cc: dev@dpdk.org
Subject: [PATCH v1 1/2] net/macb: add new driver
Date: Fri, 1 Nov 2024 10:07:19 +0000 [thread overview]
Message-ID: <1730455640-1084345-1-git-send-email-liwencheng@phytium.com.cn> (raw)
add Phytium NIC MACB ethdev PMD driver.
Signed-off-by: liwencheng <liwencheng@phytium.com.cn>
---
drivers/net/macb/base/generic_phy.c | 276 +++++
drivers/net/macb/base/generic_phy.h | 198 ++++
drivers/net/macb/base/macb_common.c | 667 +++++++++++
drivers/net/macb/base/macb_common.h | 253 +++++
drivers/net/macb/base/macb_errno.h | 54 +
drivers/net/macb/base/macb_hw.h | 1136 +++++++++++++++++++
drivers/net/macb/base/macb_type.h | 23 +
drivers/net/macb/base/macb_uio.c | 354 ++++++
drivers/net/macb/base/macb_uio.h | 50 +
drivers/net/macb/base/meson.build | 26 +
drivers/net/macb/macb_ethdev.c | 1972 +++++++++++++++++++++++++++++++++
drivers/net/macb/macb_ethdev.h | 92 ++
drivers/net/macb/macb_log.h | 19 +
drivers/net/macb/macb_rxtx.c | 1386 +++++++++++++++++++++++
drivers/net/macb/macb_rxtx.h | 325 ++++++
drivers/net/macb/macb_rxtx_vec_neon.c | 677 +++++++++++
drivers/net/macb/meson.build | 24 +
drivers/net/meson.build | 1 +
18 files changed, 7533 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/macb_rxtx_vec_neon.c
create mode 100644 drivers/net/macb/meson.build
diff --git a/drivers/net/macb/base/generic_phy.c b/drivers/net/macb/base/generic_phy.c
new file mode 100644
index 0000000..79830b0
--- /dev/null
+++ b/drivers/net/macb/base/generic_phy.c
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Phytium Technology Co., Ltd.
+ */
+
+#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;
+}
+
+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);
+}
+
+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;
+}
+
+int 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);
+ return 0;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int 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);
+ return 0;
+}
+
+int macb_usxgmii_pcs_check_for_link(struct phy_device *phydev)
+{
+ int value;
+ int link;
+ struct macb *bp = phydev->bp;
+ value = gem_readl(bp, USX_STATUS);
+ link = GEM_BFEXT(BLOCK_LOCK, value);
+ return link;
+}
+
+int macb_gbe_pcs_check_for_link(struct phy_device *phydev)
+{
+ int value;
+ int link;
+ struct macb *bp = phydev->bp;
+
+ value = macb_readl(bp, NSR);
+ link = MACB_BFEXT(NSR_LINK, value);
+ return link;
+}
+
+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,
+};
+
+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,
+};
+
+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..0453a87
--- /dev/null
+++ b/drivers/net/macb/base/generic_phy.h
@@ -0,0 +1,198 @@
+#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);
+ int (*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;
+}
+
+int genphy_soft_reset(struct phy_device *phydev);
+int genphy_resume(struct phy_device *phydev);
+int genphy_suspend(struct phy_device *phydev);
+int genphy_force_speed_duplex(struct phy_device *phydev);
+int genphy_check_for_link(struct phy_device *phydev);
+int genphy_read_status(struct phy_device *phydev);
+
+/* for usxgmii interface */
+int macb_usxgmii_pcs_resume(struct phy_device *phydev);
+int 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..9bf839d
--- /dev/null
+++ b/drivers/net/macb/base/macb_common.c
@@ -0,0 +1,667 @@
+/* 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 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 get_last_num_from_string(char *buf, int *id)
+{
+ int len = strlen(buf);
+ int i, found = 0;
+
+ for (i = len - 1; (i >= 0); i--) {
+ if (isdigit(buf[i]))
+ found++;
+ else if (found)
+ break;
+ }
+
+ if (found) {
+ *id = atoi(&buf[i + 1]);
+ return 0;
+ }
+
+ return -1;
+}
+
+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;
+}
+
+int macb_check_for_link(struct macb *bp)
+{
+ struct phy_device *phydev = bp->phydev;
+
+ if (phydev->drv && phydev->drv->check_for_link)
+ bp->link = phydev->drv->check_for_link(phydev);
+ return 0;
+}
+
+int 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);
+
+ return 0;
+}
+
+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..81319f9
--- /dev/null
+++ b/drivers/net/macb/base/macb_common.h
@@ -0,0 +1,253 @@
+/* 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;
+
+ rte_spinlock_t lock;
+ 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 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 get_last_num_from_string(char *buf, int *id);
+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);
+int macb_check_for_link(struct macb *bp);
+int 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..121ecd9
--- /dev/null
+++ b/drivers/net/macb/base/macb_errno.h
@@ -0,0 +1,54 @@
+#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..18ccc4d
--- /dev/null
+++ b/drivers/net/macb/base/macb_hw.h
@@ -0,0 +1,1136 @@
+/* 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_byte_frames;
+ 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_byte_frames;
+ 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_byte_frames"),
+ 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_byte_frames"),
+ 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..46c556e
--- /dev/null
+++ b/drivers/net/macb/base/macb_uio.c
@@ -0,0 +1,354 @@
+/* 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, unsigned long *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%lx", map_size);
+ fclose(file);
+ if (ret < 0)
+ return -2;
+
+ return 0;
+}
+
+static int uio_get_map_addr(const int udev_id, unsigned long *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%lx", 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 = malloc(strlen(name) + 1);
+ if (!new->name) {
+ MACB_LOG(ERR, "No memory for IOMEM-name obj.");
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ memcpy(new->name, name, strlen(name));
+ new->name[strlen(name)] = '\0';
+
+ 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;
+ off_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 *)((uintptr_t)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..09772a3
--- /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 {
+ unsigned long addr;
+ unsigned long 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..009850f
--- /dev/null
+++ b/drivers/net/macb/base/meson.build
@@ -0,0 +1,26 @@
+# 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..f5a2e14
--- /dev/null
+++ b/drivers/net/macb/macb_ethdev.c
@@ -0,0 +1,1972 @@
+/* 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"
+
+#ifndef MACB_DEBUG
+#define MACB_DEBUG 0
+#endif
+
+#define MACB_DRIVER_VERSION "5.6"
+#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
+
+#if MACB_PORT_MODE_SWITCH
+void *macb_phy_dl_handle;
+int (*macb_phy_init)(uint16_t port_id, uint32_t speed);
+#endif
+
+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);
+
+ /* Disable RX checksum offload */
+ if (macb_is_gem(bp))
+ cfg &= ~GEM_BIT(RXCOEN);
+ 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);
+
+ /* Enable RX checksum offload */
+ if (macb_is_gem(bp) &&
+ (bp->dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM))
+ cfg |= GEM_BIT(RXCOEN);
+ 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 int macb_interrupt_action(struct rte_eth_dev *dev)
+{
+ struct rte_eth_link link;
+ struct macb_priv *priv = dev->data->dev_private;
+ int ret;
+ char speed[16];
+
+ if (priv->stopped)
+ return 0;
+
+ ret = eth_macb_link_update(dev, 0);
+ if (ret < 0)
+ return 0;
+
+ rte_eth_linkstatus_get(dev, &link);
+ if (link.link_status) {
+ switch (link.link_speed) {
+ case RTE_ETH_SPEED_NUM_10M:
+ strcpy(speed, "10Mbps");
+ break;
+ case RTE_ETH_SPEED_NUM_100M:
+ strcpy(speed, "100Mbps");
+ break;
+ case RTE_ETH_SPEED_NUM_1G:
+ strcpy(speed, "1Gbps");
+ break;
+ case RTE_ETH_SPEED_NUM_2_5G:
+ strcpy(speed, "2.5Gbps");
+ break;
+ case RTE_ETH_SPEED_NUM_5G:
+ strcpy(speed, "5Gbps");
+ break;
+ case RTE_ETH_SPEED_NUM_10G:
+ strcpy(speed, "10Gbps");
+ break;
+ default:
+ strcpy(speed, "unknown");
+ break;
+ }
+
+ MACB_INFO(" Port %d: Link Up - speed %s - %s",
+ dev->data->port_id, speed,
+ link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX ? "full-duplex" : "half-duplex");
+ } else {
+ MACB_INFO(" Port %d: Link Down", dev->data->port_id);
+ }
+
+ macb_link_change(priv->bp);
+ rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+ return 0;
+}
+
+static void macb_interrupt_handler(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+ macb_interrupt_action(dev);
+}
+
+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;
+#if MACB_DEBUG
+ struct macb_rx_queue *rxq;
+ struct macb_tx_queue *txq;
+ uint64_t nb_rx = 0;
+ uint64_t nb_tx = 0;
+ uint64_t tx_bytes = 0;
+ uint64_t rx_bytes = 0;
+ uint32_t i;
+#endif
+
+ if (!priv->bp) {
+ MACB_LOG(ERR, "Failed to get private data!");
+ return -EPERM;
+ }
+
+ 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 -
+ priv->prev_stats.ibytes;
+ stats->obytes = hwstat->tx_octets_31_0 + hwstat->tx_octets_47_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;
+#if MACB_DEBUG
+ /* turn on while forward packets error. */
+ printf("rx_frame_check_sequence_errors: %lu\nrx_alignment_errors: "
+ "%lu\nrx_resource_drops: %lu\n"
+ "rx_overruns: %lu\nrx_oversize_frames: %lu\nrx_jabbers: "
+ "%lu\nrx_undersized_frames: %lu\n"
+ "rx_length_field_frame_errors: %lu\nrx_ip_header_checksum_errors: %lu\n"
+ "rx_tcp_checksum_errors: %lu\nrx_udp_checksum_errors: %lu\n",
+ hwstat->rx_frame_check_sequence_errors, hwstat->rx_alignment_errors,
+ hwstat->rx_resource_drops, hwstat->rx_overruns,
+ 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);
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ rxq = dev->data->rx_queues[i];
+ nb_rx += rxq->stats.rx_packets;
+ rx_bytes += rxq->stats.rx_bytes;
+ }
+ printf("nb_rx: %lu\nrx_bytes: %lu\n", nb_rx, rx_bytes);
+ printf("tx_late_collisions: %lu\ntx_excesive_collisions: %lu\ntx_underrun: "
+ "%lu\ntx_carrier_sense_errors: %lu\n",
+ hwstat->tx_late_collisions, hwstat->tx_excessive_collisions,
+ hwstat->tx_underrun, hwstat->tx_carrier_sense_errors);
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ txq = dev->data->tx_queues[i];
+ nb_tx += txq->stats.tx_packets;
+ tx_bytes += txq->stats.tx_bytes;
+ }
+ printf("nb_tx: %lu\ntx_bytes: %lu\n", nb_tx, tx_bytes);
+#endif
+ 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->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 *size __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;
+
+ if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
+ MACB_LOG(ERR, "Tried to set invalid MAC address.");
+ return -EINVAL;
+ }
+
+ 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 = 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;
+}
+
+#if MACB_PORT_MODE_SWITCH
+static void macb_switch_port_mode(struct rte_eth_dev *dev, uint32_t speed)
+{
+ struct macb_priv *priv = dev->data->dev_private;
+ phys_addr_t physical_addr = priv->physical_addr;
+ struct macb *bp = priv->bp;
+ struct phy_device *phydev = bp->phydev;
+
+ if (physical_addr == MAC0_ADDR_BASE || physical_addr == MAC1_ADDR_BASE) {
+ if (speed == RTE_ETH_LINK_SPEED_100M) {
+ bp->phy_interface = MACB_PHY_INTERFACE_MODE_100BASEX;
+ bp->speed = SPEED_100;
+ bp->duplex = DUPLEX_FULL;
+ } else if (speed == RTE_ETH_LINK_SPEED_1G) {
+ bp->phy_interface = MACB_PHY_INTERFACE_MODE_1000BASEX;
+ bp->speed = SPEED_1000;
+ bp->duplex = DUPLEX_FULL;
+ } else if (speed == RTE_ETH_LINK_SPEED_2_5G) {
+ bp->phy_interface = MACB_PHY_INTERFACE_MODE_2500BASEX;
+ bp->speed = SPEED_2500;
+ bp->duplex = DUPLEX_FULL;
+ } else if (speed == RTE_ETH_LINK_SPEED_10G) {
+ bp->phy_interface = MACB_PHY_INTERFACE_MODE_USXGMII;
+ bp->speed = SPEED_10000;
+ bp->duplex = DUPLEX_FULL;
+ }
+ }
+ /* switch phy driver */
+ if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX ||
+ bp->phy_interface == MACB_PHY_INTERFACE_MODE_1000BASEX ||
+ bp->phy_interface == MACB_PHY_INTERFACE_MODE_2500BASEX)
+ phydev->drv = &macb_gbe_pcs_driver;
+ else if (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII)
+ phydev->drv = &macb_usxgmii_pcs_driver;
+}
+#endif
+
+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);
+
+ gem_writel(bp, DMACFG, dmacfg);
+ }
+}
+
+static void macb_init_hw(struct macb *bp)
+{
+ u32 config;
+ u32 max_len;
+
+#if MACB_PORT_MODE_SWITCH
+ enum macb_port_id port_id = PORT_MAX;
+#endif
+
+ /* 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 MACB_PORT_MODE_SWITCH
+ if (bp->paddr == MAC0_ADDR_BASE)
+ port_id = PORT0;
+ else if (bp->paddr == MAC1_ADDR_BASE)
+ port_id = PORT1;
+
+ if (port_id != PORT_MAX && macb_phy_init != NULL)
+ if (macb_phy_init(port_id, bp->speed))
+ MACB_LOG(ERR, "Failed to init macb phy!");
+#endif
+
+ 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;
+#if MACB_PORT_MODE_SWITCH
+ uint32_t speed;
+#endif
+
+ /* Make sure the phy device is disabled */
+ eth_macb_dev_set_link_down(dev);
+
+#if MACB_PORT_MODE_SWITCH
+ /* switch port mode */
+ speed = dev->data->dev_conf.link_speeds;
+ if (speed & RTE_ETH_LINK_SPEED_FIXED)
+ speed &= ~RTE_ETH_LINK_SPEED_FIXED;
+
+ if ((bp->phy_interface == MACB_PHY_INTERFACE_MODE_100BASEX &&
+ speed != RTE_ETH_LINK_SPEED_100M) || (bp->phy_interface ==
+ MACB_PHY_INTERFACE_MODE_1000BASEX && speed != RTE_ETH_LINK_SPEED_1G) ||
+ (bp->phy_interface == MACB_PHY_INTERFACE_MODE_USXGMII &&
+ speed != RTE_ETH_LINK_SPEED_10G) || (bp->phy_interface ==
+ MACB_PHY_INTERFACE_MODE_2500BASEX && speed != RTE_ETH_LINK_SPEED_2_5G)) {
+ macb_switch_port_mode(dev, speed);
+ }
+#endif
+
+ /* 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 */
+ eth_macb_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 = eth_macb_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 = eth_macb_rx_queue_setup,
+ .tx_queue_setup = eth_macb_tx_queue_setup,
+ .rx_queue_release = eth_macb_rx_queue_release,
+ .tx_queue_release = eth_macb_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\n");
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ dev->rx_pkt_burst = eth_macb_recv_pkts;
+ dev->tx_pkt_burst = eth_macb_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_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;
+ goto out_free;
+ }
+ }
+
+ if (rte_intr_fd_set(priv->intr_handle, bp->iomem->fd))
+ return -rte_errno;
+
+ if (rte_intr_type_set(priv->intr_handle, RTE_INTR_HANDLE_UIO))
+ 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;
+ char *s;
+ char filename[MAX_FILE_LEN];
+
+ snprintf(filename, MAX_FILE_LEN, "%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;
+ }
+
+ pclk_hz = malloc(CLK_STR_LEN);
+ if (!pclk_hz) {
+ MACB_LOG(ERR, "no mem for pclk_hz.");
+ return -ENOMEM;
+ }
+ 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);
+ free(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;
+ char *s;
+ int i;
+ char filename[MAX_FILE_LEN];
+
+ snprintf(filename, MAX_FILE_LEN, "%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;
+ }
+
+ phy_mode = malloc(PHY_MODE_LEN);
+ if (!phy_mode) {
+ MACB_LOG(ERR, "no mem for phy_mode.");
+ return -ENOMEM;
+ }
+ 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) {
+ MACB_LOG(ERR, "Invalid phy_mode value: %s!", phy_mode);
+ return -EINVAL;
+ }
+
+ free(phy_mode);
+ 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;
+ char *s;
+ char *stopstr;
+ char filename[MAX_FILE_LEN];
+
+ snprintf(filename, MAX_FILE_LEN, "%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;
+ }
+
+ physical_addr = malloc(PHY_ADDR_LEN);
+ if (!physical_addr) {
+ MACB_LOG(ERR, "no mem for physical_addr.");
+ return -ENOMEM;
+ }
+ 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);
+ free(physical_addr);
+ 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;
+ char *s;
+ char filename[MAX_FILE_LEN];
+ priv->dev_type = DEV_TYPE_DEFAULT;
+
+ snprintf(filename, MAX_FILE_LEN, "%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;
+ }
+
+ dev_type = malloc(DEV_TYPE_LEN);
+ if (!dev_type) {
+ MACB_LOG(ERR, "no mem for dev_type.");
+ return -ENOMEM;
+ }
+ 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 {
+ MACB_LOG(ERR, "Unsupported device type: %s.", dev_type);
+ return -EINVAL;
+ }
+
+ free(dev_type);
+ fclose(file);
+ return 0;
+}
+
+static int macb_get_speed_info(struct rte_eth_dev *dev, char *speed_info)
+{
+ char filename[MAX_FILE_LEN];
+ char *s;
+ struct macb_priv *priv = dev->data->dev_private;
+
+ if (!speed_info) {
+ MACB_LOG(ERR, "speed info is NULL.");
+ return -ENOMEM;
+ }
+
+ snprintf(filename, MAX_FILE_LEN, "%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;
+ char *duplex = NULL;
+ int ret = 0;
+
+ speed_info = malloc(SPEED_INFO_LEN);
+ if (!speed_info) {
+ MACB_LOG(ERR, "no mem for speed_info.");
+ return -ENOMEM;
+ }
+ 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;
+ }
+
+ free(speed_info);
+ 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;
+ 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);
+ }
+
+#if MACB_PORT_MODE_SWITCH
+ dlclose(macb_phy_dl_handle);
+#endif
+
+ 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;
+
+#if MACB_PORT_MODE_SWITCH
+ macb_phy_dl_handle = dlopen(LIB_PHY_NAME, RTLD_LAZY);
+ if (!macb_phy_dl_handle) {
+ MACB_LOG(ERR, "Failed load library: %s", dlerror());
+ return -1;
+ }
+ macb_phy_init = dlsym(macb_phy_dl_handle, "phytium_serdes_phy_init");
+ if (!macb_phy_init) {
+ MACB_LOG(ERR, "Failed to resolve symbol: %s", dlerror());
+ return -1;
+ }
+#endif
+
+ 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\n");
+ return -EINVAL;
+ }
+
+ rte_log_set_level(macb_logtype, rte_log_get_global_level());
+
+ 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_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");
+ if (macb_logtype >= 0)
+ rte_log_set_level(macb_logtype, RTE_LOG_NOTICE);
+
+ 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..580d3d4
--- /dev/null
+++ b/drivers/net/macb/macb_ethdev.h
@@ -0,0 +1,92 @@
+/* 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_FILE_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;
+
+#ifndef MACB_PORT_MODE_SWITCH
+#define MACB_PORT_MODE_SWITCH 0
+#endif
+
+#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))
+
+#if MACB_PORT_MODE_SWITCH
+#define LIB_PHY_NAME "libpe2204phy.so"
+#define MAC0_ADDR_BASE 0x3200c000
+#define MAC1_ADDR_BASE 0x3200e000
+
+enum macb_port_id {
+ PORT0,
+ PORT1,
+ PORT_MAX
+};
+#endif
+
+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..cd2eecb
--- /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 MACB_LOG(level, fmt, args...) \
+ rte_log(RTE_LOG_ ## level, macb_logtype, "%s(): " fmt "\n", \
+ __func__, ##args)
+
+#define MACB_INFO(fmt, args...) \
+ rte_log(RTE_LOG_INFO, macb_logtype, "MACB: " fmt "\n", \
+ ##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..5d1aea9
--- /dev/null
+++ b/drivers/net/macb/macb_rxtx.c
@@ -0,0 +1,1386 @@
+/* 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 eth_macb_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;
+ 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);
+ 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 eth_macb_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;
+ uint16_t ether_type;
+
+ 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_smp_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\n");
+ 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);
+ 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;
+
+ 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;
+
+ 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))
+ 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;
+
+ /*
+ * 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,
+ * 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;
+ }
+
+out:
+ return nb_rx;
+}
+
+uint16_t eth_macb_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.
+ */
+ 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;
+ uint16_t ether_type;
+
+ 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_smp_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;
+
+ if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))
+ 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;
+ /*
+ * 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 eth_macb_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 = eth_macb_xmit_pkts_vec;
+ }
+ } else {
+ dev->tx_pkt_burst = eth_macb_xmit_pkts;
+ }
+}
+
+int __rte_cold eth_macb_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 __rte_cold 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 eth_macb_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 eth_macb_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++) {
+ eth_macb_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++) {
+ eth_macb_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)
+{
+ static const struct macb_dma_desc zeroed_desc = {0};
+ 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 = zeroed_desc;
+ }
+
+ rxdesc = macb_rx_desc(rxq, rxq->nb_rx_desc - 1);
+ for (i = 0; i < MACB_DESCS_PER_LOOP; i++) {
+ rxdesc += MACB_DESC_ADDR_INTERVAL;
+ *rxdesc = zeroed_desc;
+ }
+
+ /*
+ * 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 eth_macb_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;
+
+ /*
+ * 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;
+ 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;
+
+ /*
+ * 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;
+ }
+
+ 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);
+ 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_smp_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 = eth_macb_recv_scattered_pkts_vec;
+ } else {
+ MACB_INFO("Using Regular (non-vector) "
+ "Scattered Rx callback "
+ "(port=%d).",
+ dev->data->port_id);
+ dev->rx_pkt_burst = eth_macb_recv_scattered_pkts;
+ }
+ } else {
+ if (bp->rx_vec_allowed) {
+ MACB_INFO("Vector rx enabled");
+ dev->rx_pkt_burst = eth_macb_recv_pkts_vec;
+ } else {
+ dev->rx_pkt_burst = eth_macb_recv_pkts;
+ }
+ }
+}
+
+int __rte_cold 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 eth_macb_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;
+}
+
+/* Stubs needed for linkage when RTE_ARCH_PPC_64, RTE_ARCH_RISCV or
+ * RTE_ARCH_LOONGARCH is set.
+ */
+#if defined(RTE_ARCH_PPC_64) || defined(RTE_ARCH_RISCV) || \
+ defined(RTE_ARCH_LOONGARCH) || defined(RTE_ARCH_X86)
+uint16_t
+eth_macb_recv_pkts_vec(void __rte_unused *rx_queue,
+ struct rte_mbuf __rte_unused **rx_pkts,
+ uint16_t __rte_unused nb_pkts)
+{
+ return 0;
+}
+
+uint16_t
+eth_macb_recv_scattered_pkts_vec(void __rte_unused *rx_queue,
+ struct rte_mbuf __rte_unused **rx_pkts,
+ uint16_t __rte_unused nb_pkts)
+{
+ return 0;
+}
+
+uint16_t
+eth_macb_xmit_pkts_vec(void __rte_unused *tx_queue,
+ struct rte_mbuf __rte_unused **tx_pkts,
+ uint16_t __rte_unused nb_pkts)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/net/macb/macb_rxtx.h b/drivers/net/macb/macb_rxtx.h
new file mode 100644
index 0000000..8d8e471
--- /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 macb_rx_queue_stats {
+ union {
+ unsigned long first;
+ unsigned long rx_packets;
+ };
+ unsigned long rx_bytes;
+ unsigned long rx_dropped;
+};
+
+struct macb_tx_queue_stats {
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+ unsigned long tx_dropped;
+ unsigned long tx_start_packets;
+ unsigned long 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 __rte_aligned(RTE_CACHE_LINE_SIZE);
+ 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 __rte_aligned(RTE_CACHE_LINE_SIZE);
+};
+
+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 eth_macb_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 eth_macb_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
+ unsigned int socket, const struct rte_eth_txconf *conf);
+void eth_macb_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
+void eth_macb_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
+void macb_dev_free_queues(struct rte_eth_dev *dev);
+uint16_t eth_macb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t eth_macb_xmit_pkts_vec(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t eth_macb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t eth_macb_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t eth_macb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t eth_macb_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 __rte_cold macb_rx_phyaddr_check(struct rte_eth_dev *dev);
+int __rte_cold macb_tx_phyaddr_check(struct rte_eth_dev *dev);
+int eth_macb_rx_init(struct rte_eth_dev *dev);
+void eth_macb_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/macb_rxtx_vec_neon.c b/drivers/net/macb/macb_rxtx_vec_neon.c
new file mode 100644
index 0000000..1110c39
--- /dev/null
+++ b/drivers/net/macb/macb_rxtx_vec_neon.c
@@ -0,0 +1,677 @@
+/* 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_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_vect.h>
+#include <stdint.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"
+
+#pragma GCC diagnostic ignored "-Wcast-qual"
+
+#define MACB_UINT8_BIT (CHAR_BIT * sizeof(uint8_t))
+
+#define MACB_DESC_EOF_MASK 0x80808080
+
+static inline uint32_t macb_get_packet_type(struct rte_mbuf *rxm)
+{
+ struct rte_ether_hdr *eth_hdr;
+ uint16_t ether_type;
+
+ 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))
+ return RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4;
+ else if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6))
+ return RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6;
+ else
+ return RTE_PTYPE_UNKNOWN;
+}
+
+static inline uint8x8_t macb_mbuf_initializer(struct macb_rx_queue *rxq)
+{
+ struct rte_mbuf mbuf = {.buf_addr = 0}; /* zeroed mbuf */
+ uint64x1_t mbuf_initializer;
+ uint8x8_t rearm_data_vec;
+
+ mbuf.data_off = RTE_PKTMBUF_HEADROOM + MACB_RX_DATA_OFFSET;
+ mbuf.nb_segs = 1;
+ mbuf.port = rxq->port_id;
+ rte_mbuf_refcnt_set(&mbuf, 1);
+
+ /* prevent compiler reordering: rearm_data covers previous fields */
+ rte_compiler_barrier();
+ mbuf_initializer =
+ vset_lane_u64(*(uint64_t *)(&mbuf.rearm_data), mbuf_initializer, 0);
+ rearm_data_vec = vld1_u8((uint8_t *)&mbuf_initializer);
+ return rearm_data_vec;
+}
+
+static inline void macb_rxq_rearm(struct macb_rx_queue *rxq)
+{
+ uint64_t dma_addr;
+ struct macb_dma_desc *desc;
+ unsigned int entry;
+ struct rte_mbuf *nmb;
+ struct macb *bp;
+ register int i = 0;
+ struct macb_rx_entry *rxe;
+
+ uint32x2_t zero = vdup_n_u32(0);
+ uint8x8_t rearm_data_vec;
+
+ bp = rxq->bp;
+ rxe = &rxq->rx_sw_ring[rxq->rxrearm_start];
+
+ entry = macb_rx_ring_wrap(bp, rxq->rxrearm_start);
+ desc = macb_rx_desc(rxq, entry);
+
+ rearm_data_vec = macb_mbuf_initializer(rxq);
+
+ /* Pull 'n' more MBUFs into the software ring */
+ if (unlikely(rte_mempool_get_bulk(rxq->mb_pool, (void *)rxe,
+ MACB_RXQ_REARM_THRESH) < 0)) {
+ if (rxq->rxrearm_nb + (unsigned int)MACB_RXQ_REARM_THRESH >=
+ rxq->nb_rx_desc) {
+ MACB_LOG(ERR, "allocate mbuf fail!\n");
+ for (i = 0; i < MACB_DESCS_PER_LOOP; i++) {
+ rxe[i].mbuf = &rxq->fake_mbuf;
+ vst1_u32((uint32_t *)&desc[MACB_DESC_ADDR_INTERVAL * i], zero);
+ }
+ }
+ rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed +=
+ MACB_RXQ_REARM_THRESH;
+ return;
+ }
+
+ for (i = 0; i < MACB_RXQ_REARM_THRESH; ++i) {
+ nmb = rxe[i].mbuf;
+ entry = macb_rx_ring_wrap(bp, rxq->rxrearm_start);
+ desc = macb_rx_desc(rxq, entry);
+ rxq->rxrearm_start++;
+ vst1_u8((uint8_t *)&nmb->rearm_data, rearm_data_vec);
+ dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
+ if (unlikely(entry == rxq->nb_rx_desc - 1))
+ dma_addr |= MACB_BIT(RX_WRAP);
+ 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);
+ }
+ if (unlikely(rxq->rxrearm_start >= rxq->nb_rx_desc))
+ rxq->rxrearm_start = 0;
+ rxq->rxrearm_nb -= MACB_RXQ_REARM_THRESH;
+}
+
+static inline void macb_pkts_to_ptype_v(struct rte_mbuf **rx_pkts)
+{
+ if (likely(rx_pkts[0]->buf_addr != NULL))
+ rx_pkts[0]->packet_type = macb_get_packet_type(rx_pkts[0]);
+
+ if (likely(rx_pkts[1]->buf_addr != NULL))
+ rx_pkts[1]->packet_type = macb_get_packet_type(rx_pkts[1]);
+
+ if (likely(rx_pkts[2]->buf_addr != NULL))
+ rx_pkts[2]->packet_type = macb_get_packet_type(rx_pkts[2]);
+
+ if (likely(rx_pkts[3]->buf_addr != NULL))
+ rx_pkts[3]->packet_type = macb_get_packet_type(rx_pkts[3]);
+}
+
+static inline void macb_pkts_to_port_v(struct rte_mbuf **rx_pkts, uint16_t port_id)
+{
+ rx_pkts[0]->port = port_id;
+ rx_pkts[1]->port = port_id;
+ rx_pkts[2]->port = port_id;
+ rx_pkts[3]->port = port_id;
+}
+
+static inline void macb_free_rx_pkts(struct macb_rx_queue *rxq,
+ struct rte_mbuf **rx_pkts, int pos, uint16_t count)
+{
+ for (int j = 0; j < count; j++) {
+ if (likely(rx_pkts[pos + j] != NULL)) {
+ rte_pktmbuf_free_seg(rx_pkts[pos + j]);
+ rx_pkts[pos + j] = NULL;
+ }
+ }
+ rxq->rx_tail += count;
+ rxq->rxrearm_nb += count;
+ rxq->stats.rx_dropped += count;
+}
+
+static uint16_t macb_recv_raw_pkts_vec(struct macb_rx_queue *rxq,
+ struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts, uint8_t *split_packet)
+{
+ struct macb_dma_desc *desc;
+ struct macb_rx_entry *rx_sw_ring;
+ struct macb_rx_entry *rxn;
+ uint16_t nb_pkts_recv = 0;
+ register uint16_t pos;
+ uint16_t bytes_len = 0;
+
+ uint8x16_t shuf_msk = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 0xFF, 0xFF,
+ 4, 5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+ uint16x8_t crc_adjust = {0, 0, rxq->crc_len, 0, rxq->crc_len, 0, 0, 0};
+
+ /* nb_pkts shall be less equal than MACB_MAX_RX_BURST */
+ nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, MACB_DESCS_PER_LOOP);
+ nb_pkts = RTE_MIN(nb_pkts, MACB_MAX_RX_BURST);
+
+ desc = rxq->rx_ring + rxq->rx_tail * MACB_DESC_ADDR_INTERVAL;
+ rte_prefetch_non_temporal(desc);
+
+ if (rxq->rxrearm_nb >= MACB_RXQ_REARM_THRESH)
+ macb_rxq_rearm(rxq);
+
+ /* Make hw descriptor updates visible to CPU */
+ rte_rmb();
+
+ /* Before we start moving massive data around, check to see if
+ * there is actually a packet available
+ */
+ if (!((desc->addr & MACB_BIT(RX_USED)) ? true : false))
+ return 0;
+
+ rx_sw_ring = &rxq->rx_sw_ring[rxq->rx_tail];
+ /* A. load 4 packet in one loop
+ * B. copy 4 mbuf point from swring to rx_pkts
+ * C. calc the number of RX_USED bits among the 4 packets
+ * D. fill info. from desc to mbuf
+ */
+ for (pos = 0, nb_pkts_recv = 0; pos < nb_pkts; pos += MACB_DESCS_PER_LOOP,
+ desc += MACB_DESCS_PER_LOOP * MACB_DESC_ADDR_INTERVAL) {
+ uint64x2_t mbp1, mbp2;
+ uint64x2_t descs[MACB_DESCS_PER_LOOP];
+ uint8x16x2_t sterr_tmp1, sterr_tmp2;
+ uint8x16_t staterr;
+ uint8x16_t pkt_mb1, pkt_mb2, pkt_mb3, pkt_mb4;
+ uint16x8_t pkt_mb_mask;
+ uint16x8_t tmp;
+ uint16_t cur_bytes_len[MACB_DESCS_PER_LOOP] = {0, 0, 0, 0};
+ uint32_t stat;
+ uint16_t nb_used = 0;
+ uint16_t i;
+
+ /* B.1 load 2 mbuf point */
+ mbp1 = vld1q_u64((uint64_t *)&rx_sw_ring[pos]);
+ /* B.2 copy 2 mbuf point into rx_pkts */
+ vst1q_u64((uint64_t *)&rx_pkts[pos], mbp1);
+
+ /* B.1 load 2 mbuf point */
+ mbp2 = vld1q_u64((uint64_t *)&rx_sw_ring[pos + 2]);
+ /* B.2 copy 2 mbuf point into rx_pkts */
+ vst1q_u64((uint64_t *)&rx_pkts[pos + 2], mbp2);
+
+ rte_mbuf_prefetch_part2(rx_pkts[pos]);
+ rte_mbuf_prefetch_part2(rx_pkts[pos + 1]);
+ rte_mbuf_prefetch_part2(rx_pkts[pos + 2]);
+ rte_mbuf_prefetch_part2(rx_pkts[pos + 3]);
+
+ /* A. load 4 pkts descs */
+ descs[0] = vld1q_u64((uint64_t *)(desc));
+ descs[1] = vld1q_u64((uint64_t *)(desc + 1 * MACB_DESC_ADDR_INTERVAL));
+ descs[2] = vld1q_u64((uint64_t *)(desc + 2 * MACB_DESC_ADDR_INTERVAL));
+ descs[3] = vld1q_u64((uint64_t *)(desc + 3 * MACB_DESC_ADDR_INTERVAL));
+
+ rxn = &rx_sw_ring[pos + 0 + MACB_NEON_PREFETCH_ENTRY];
+ rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
+ rxn = &rx_sw_ring[pos + 1 + MACB_NEON_PREFETCH_ENTRY];
+ rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
+ rxn = &rx_sw_ring[pos + 2 + MACB_NEON_PREFETCH_ENTRY];
+ rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
+ rxn = &rx_sw_ring[pos + 3 + MACB_NEON_PREFETCH_ENTRY];
+ rte_prefetch0((char *)rxn->mbuf->buf_addr + rxn->mbuf->data_off);
+
+ /* D.1 pkt convert format from desc to pktmbuf */
+ pkt_mb1 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[0]), shuf_msk);
+ pkt_mb2 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[1]), shuf_msk);
+ pkt_mb3 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[2]), shuf_msk);
+ pkt_mb4 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[3]), shuf_msk);
+
+ /* D.2 pkt 1,2 set length and remove crc */
+ if (split_packet)
+ pkt_mb_mask = vdupq_n_u16(MACB_RX_JFRMLEN_MASK);
+ else
+ pkt_mb_mask = vdupq_n_u16(MACB_RX_FRMLEN_MASK);
+
+ tmp = vsubq_u16(vandq_u16(vreinterpretq_u16_u8(pkt_mb1), pkt_mb_mask), crc_adjust);
+ pkt_mb1 = vreinterpretq_u8_u16(tmp);
+ cur_bytes_len[0] = vgetq_lane_u16(tmp, 2);
+
+ tmp = vsubq_u16(vandq_u16(vreinterpretq_u16_u8(pkt_mb2), pkt_mb_mask), crc_adjust);
+ pkt_mb2 = vreinterpretq_u8_u16(tmp);
+ cur_bytes_len[1] = vgetq_lane_u16(tmp, 2);
+
+ vst1q_u8((uint8_t *)&rx_pkts[pos]->rx_descriptor_fields1, pkt_mb1);
+ vst1q_u8((uint8_t *)&rx_pkts[pos + 1]->rx_descriptor_fields1, pkt_mb2);
+
+ /* D.2 pkt 3,4 length and remove crc */
+ tmp = vsubq_u16(vandq_u16(vreinterpretq_u16_u8(pkt_mb3), pkt_mb_mask), crc_adjust);
+ pkt_mb3 = vreinterpretq_u8_u16(tmp);
+ cur_bytes_len[2] = vgetq_lane_u16(tmp, 2);
+
+ tmp = vsubq_u16(vandq_u16(vreinterpretq_u16_u8(pkt_mb4), pkt_mb_mask), crc_adjust);
+ pkt_mb4 = vreinterpretq_u8_u16(tmp);
+ cur_bytes_len[3] = vgetq_lane_u16(tmp, 2);
+
+ vst1q_u8((void *)&rx_pkts[pos + 2]->rx_descriptor_fields1, pkt_mb3);
+ vst1q_u8((void *)&rx_pkts[pos + 3]->rx_descriptor_fields1, pkt_mb4);
+
+ /*C.1 filter RX_USED or SOF_EOF info only */
+ sterr_tmp1 = vzipq_u8(vreinterpretq_u8_u64(descs[0]),
+ vreinterpretq_u8_u64(descs[2]));
+ sterr_tmp2 = vzipq_u8(vreinterpretq_u8_u64(descs[1]),
+ vreinterpretq_u8_u64(descs[3]));
+
+ /* C* extract and record EOF bit */
+ if (split_packet) {
+ uint8x16_t eof;
+
+ eof = vzipq_u8(sterr_tmp1.val[0], sterr_tmp2.val[0]).val[1];
+ stat = vgetq_lane_u32(vreinterpretq_u32_u8(eof), 1);
+ /* and with mask to extract bits, flipping 1-0 */
+ *(int *)split_packet = ~stat & MACB_DESC_EOF_MASK;
+
+ split_packet += MACB_DESCS_PER_LOOP;
+ }
+
+ /* C.2 get 4 pkts RX_USED value */
+ staterr = vzipq_u8(sterr_tmp1.val[0], sterr_tmp2.val[0]).val[0];
+
+ /* C.3 expand RX_USED bit to saturate UINT8 */
+ staterr = vshlq_n_u8(staterr, MACB_UINT8_BIT - 1);
+ staterr = vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_u8(staterr),
+ MACB_UINT8_BIT - 1));
+ stat = ~vgetq_lane_u32(vreinterpretq_u32_u8(staterr), 0);
+
+ rte_prefetch_non_temporal(desc + MACB_DESCS_PER_LOOP *
+ MACB_DESC_ADDR_INTERVAL);
+
+ /* C.4 calc available number of desc */
+ if (unlikely(stat == 0))
+ nb_used = MACB_DESCS_PER_LOOP;
+ else
+ nb_used = __builtin_ctz(stat) / MACB_UINT8_BIT;
+
+ macb_pkts_to_ptype_v(&rx_pkts[pos]);
+ macb_pkts_to_port_v(&rx_pkts[pos], rxq->port_id);
+
+ if (nb_used == MACB_DESCS_PER_LOOP) {
+ if (split_packet == NULL) {
+ uint8x16_t sof_eof;
+
+ sof_eof = vzipq_u8(sterr_tmp1.val[0], sterr_tmp2.val[0]).val[1];
+ sof_eof = vreinterpretq_u8_s8
+ (vshrq_n_s8(vreinterpretq_s8_u8(sof_eof),
+ MACB_UINT8_BIT - 2));
+
+ /*get 4 pkts SOF_EOF value*/
+ stat = ~vgetq_lane_u32(vreinterpretq_u32_u8(sof_eof), 1);
+ if (unlikely(stat != 0)) {
+ MACB_LOG(ERR, "not whole frame pointed by descriptor\n");
+ macb_free_rx_pkts(rxq, rx_pkts, pos, MACB_DESCS_PER_LOOP);
+ goto out;
+ }
+ }
+ } else {
+ u32 ctrl;
+
+ if (split_packet == NULL) {
+ for (i = 0; i < nb_used; i++, desc += MACB_DESC_ADDR_INTERVAL) {
+ ctrl = desc->ctrl;
+ 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\n");
+ macb_free_rx_pkts(rxq, rx_pkts, pos, nb_used);
+ goto out;
+ }
+ }
+ }
+ }
+
+ nb_pkts_recv += nb_used;
+ for (i = 0; i < nb_used; i++)
+ bytes_len += (cur_bytes_len[i] + rxq->crc_len);
+
+ if (nb_used < MACB_DESCS_PER_LOOP)
+ break;
+ }
+
+out:
+ rxq->stats.rx_bytes += (unsigned long)bytes_len;
+ rxq->stats.rx_packets += nb_pkts_recv;
+ /* Update our internal tail pointer */
+ rxq->rx_tail = (uint16_t)(rxq->rx_tail + nb_pkts_recv);
+ rxq->rx_tail = (uint16_t)(rxq->rx_tail & (rxq->nb_rx_desc - 1));
+ rxq->rxrearm_nb = (uint16_t)(rxq->rxrearm_nb + nb_pkts_recv);
+ /* Make descriptor updates visible to hardware */
+ rte_smp_wmb();
+
+ return nb_pkts_recv;
+}
+
+uint16_t eth_macb_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts)
+{
+ return macb_recv_raw_pkts_vec(rx_queue, rx_pkts, nb_pkts, NULL);
+}
+
+static inline uint16_t macb_reassemble_packets(struct macb_rx_queue *rxq,
+ struct rte_mbuf **rx_bufs,
+ uint16_t nb_bufs,
+ uint8_t *split_flags)
+{
+ struct rte_mbuf *pkts[nb_bufs]; /*finished pkts*/
+ struct rte_mbuf *start = rxq->pkt_first_seg;
+ struct rte_mbuf *end = rxq->pkt_last_seg;
+ unsigned int pkt_idx, buf_idx;
+ struct rte_mbuf *curr = rxq->pkt_last_seg;
+ uint16_t data_bus_width_mask;
+
+ data_bus_width_mask = MACB_DATA_BUS_WIDTH_MASK(rxq->bp->data_bus_width);
+ for (buf_idx = 0, pkt_idx = 0; buf_idx < nb_bufs; buf_idx++) {
+ uint16_t len = 0;
+
+ if (end != NULL) {
+ /* processing a split packet */
+ end = rx_bufs[buf_idx];
+ curr->next = end;
+ len = end->data_len + rxq->crc_len;
+ end->data_len =
+ len ? (len - start->pkt_len) : rxq->bp->rx_buffer_size;
+ end->data_off = RTE_PKTMBUF_HEADROOM & ~data_bus_width_mask;
+
+ start->nb_segs++;
+ rxq->stats.rx_packets--;
+ start->pkt_len += end->data_len;
+
+ if (!split_flags[buf_idx]) {
+ end->next = NULL;
+ /* we need to strip crc for the whole packet */
+ if (unlikely(rxq->crc_len > 0)) {
+ start->pkt_len -= RTE_ETHER_CRC_LEN;
+ if (end->data_len > RTE_ETHER_CRC_LEN) {
+ end->data_len -= RTE_ETHER_CRC_LEN;
+ } else {
+ start->nb_segs--;
+ curr->data_len -= RTE_ETHER_CRC_LEN - end->data_len;
+ curr->next = NULL;
+ /* free up last mbuf */
+ rte_pktmbuf_free_seg(end);
+ }
+ }
+ pkts[pkt_idx++] = start;
+ start = NULL;
+ end = NULL;
+ } else {
+ curr = curr->next;
+ }
+ } else {
+ /* not processing a split packet */
+ if (!split_flags[buf_idx]) {
+ /* not a split packet, save and skip */
+ pkts[pkt_idx++] = rx_bufs[buf_idx];
+ continue;
+ }
+ start = rx_bufs[buf_idx];
+ start->pkt_len = rxq->bp->rx_buffer_size - MACB_RX_DATA_OFFSET
+ - (RTE_PKTMBUF_HEADROOM & data_bus_width_mask);
+ start->data_len = start->pkt_len;
+ start->port = rxq->port_id;
+ curr = start;
+ end = start;
+ }
+ }
+
+ /* save the partial packet for next time */
+ rxq->pkt_first_seg = start;
+ rxq->pkt_last_seg = end;
+ rte_memcpy(rx_bufs, pkts, pkt_idx * (sizeof(*pkts)));
+ return pkt_idx;
+}
+
+static uint16_t eth_macb_recv_scattered_burst_vec(void *rx_queue,
+ struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts)
+{
+ struct macb_rx_queue *rxq = rx_queue;
+ uint8_t split_flags[MACB_MAX_RX_BURST] = {0};
+ uint16_t nb_bufs;
+ const uint64_t *split_fl64;
+ uint16_t i;
+ uint16_t reassemble_packets;
+
+ /* get some new buffers */
+ nb_bufs = macb_recv_raw_pkts_vec(rxq, rx_pkts, nb_pkts, split_flags);
+ if (nb_bufs == 0)
+ return 0;
+
+ /* happy day case, full burst + no packets to be joined */
+ split_fl64 = (uint64_t *)split_flags;
+ if (rxq->pkt_first_seg == NULL && split_fl64[0] == 0 &&
+ split_fl64[1] == 0 && split_fl64[2] == 0 && split_fl64[3] == 0)
+ return nb_bufs;
+
+ /* reassemble any packets that need reassembly*/
+ i = 0;
+ if (rxq->pkt_first_seg == NULL) {
+ /* find the first split flag, and only reassemble then*/
+ while (i < nb_bufs && !split_flags[i])
+ i++;
+ if (i == nb_bufs)
+ return nb_bufs;
+ }
+
+ reassemble_packets = macb_reassemble_packets(rxq, &rx_pkts[i], nb_bufs - i,
+ &split_flags[i]);
+ return i + reassemble_packets;
+}
+
+uint16_t eth_macb_recv_scattered_pkts_vec(void *rx_queue,
+ struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts)
+{
+ uint16_t retval = 0;
+
+ while (nb_pkts > MACB_MAX_RX_BURST) {
+ uint16_t burst;
+
+ burst = eth_macb_recv_scattered_burst_vec(rx_queue, rx_pkts + retval,
+ MACB_MAX_RX_BURST);
+ retval += burst;
+ nb_pkts -= burst;
+ if (burst < MACB_MAX_RX_BURST)
+ return retval;
+ }
+
+ return retval + eth_macb_recv_scattered_burst_vec(rx_queue,
+ rx_pkts + retval, nb_pkts);
+}
+
+static inline void macb_set_txdesc(struct macb_tx_queue *queue,
+ struct macb_dma_desc *txdesc,
+ struct rte_mbuf **tx_pkts, unsigned int pos)
+{
+ uint32x4_t ctrl_v = vdupq_n_u32(0);
+ uint32x4_t data_len_v = vdupq_n_u32(0);
+ uint32x4_t BIT_TX_USED = vdupq_n_u32(MACB_BIT(TX_USED));
+ uint32x4_t BIT_TX_LAST = vdupq_n_u32(MACB_BIT(TX_LAST));
+ uint32x4_t BIT_TX_WARP = vdupq_n_u32(0);
+ uint32x4_t BIT_TX_UNUSED = vdupq_n_u32(~MACB_BIT(TX_USED));
+ uint64_t buf_dma_addr;
+
+ data_len_v =
+ vsetq_lane_u32((uint32_t)(tx_pkts[0]->data_len), data_len_v, 0);
+ data_len_v =
+ vsetq_lane_u32((uint32_t)(tx_pkts[1]->data_len), data_len_v, 1);
+ data_len_v =
+ vsetq_lane_u32((uint32_t)(tx_pkts[2]->data_len), data_len_v, 2);
+ data_len_v =
+ vsetq_lane_u32((uint32_t)(tx_pkts[3]->data_len), data_len_v, 3);
+
+ ctrl_v = vorrq_u32(vorrq_u32(data_len_v, BIT_TX_USED), BIT_TX_LAST);
+
+ if (unlikely(pos + MACB_DESCS_PER_LOOP == queue->nb_tx_desc)) {
+ BIT_TX_WARP = vsetq_lane_u32(MACB_BIT(TX_WRAP), BIT_TX_WARP, 3);
+ ctrl_v = vorrq_u32(ctrl_v, BIT_TX_WARP);
+ }
+
+ buf_dma_addr = rte_mbuf_data_iova(tx_pkts[0]);
+ macb_set_addr(queue->bp, txdesc, buf_dma_addr);
+ buf_dma_addr = rte_mbuf_data_iova(tx_pkts[1]);
+ macb_set_addr(queue->bp, txdesc + 1 * MACB_DESC_ADDR_INTERVAL,
+ buf_dma_addr);
+ buf_dma_addr = rte_mbuf_data_iova(tx_pkts[2]);
+ macb_set_addr(queue->bp, txdesc + 2 * MACB_DESC_ADDR_INTERVAL,
+ buf_dma_addr);
+ buf_dma_addr = rte_mbuf_data_iova(tx_pkts[3]);
+ macb_set_addr(queue->bp, txdesc + 3 * MACB_DESC_ADDR_INTERVAL,
+ buf_dma_addr);
+
+ ctrl_v = vandq_u32(ctrl_v, BIT_TX_UNUSED);
+ rte_wmb();
+
+ txdesc->ctrl = vgetq_lane_u32(ctrl_v, 0);
+ (txdesc + 1 * MACB_DESC_ADDR_INTERVAL)->ctrl = vgetq_lane_u32(ctrl_v, 1);
+ (txdesc + 2 * MACB_DESC_ADDR_INTERVAL)->ctrl = vgetq_lane_u32(ctrl_v, 2);
+ (txdesc + 3 * MACB_DESC_ADDR_INTERVAL)->ctrl = vgetq_lane_u32(ctrl_v, 3);
+}
+
+static inline uint16_t
+macb_xmit_pkts_vec(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ struct macb_tx_queue *queue;
+ struct macb_tx_entry *txe;
+ struct macb_dma_desc *txdesc;
+ struct macb *bp;
+ uint32_t tx_tail;
+ uint16_t nb_xmit_vec;
+ uint16_t nb_tx;
+ uint16_t nb_txok;
+ uint16_t nb_idx;
+ uint64x2_t mbp1, mbp2;
+ uint16x4_t nb_segs_v = vdup_n_u16(0);
+
+ queue = (struct macb_tx_queue *)tx_queue;
+ bp = queue->bp;
+ nb_tx = 0;
+
+ nb_xmit_vec = nb_pkts - nb_pkts % MACB_DESCS_PER_LOOP;
+ tx_tail = queue->tx_tail;
+ txe = &queue->tx_sw_ring[tx_tail];
+ txdesc = queue->tx_ring + tx_tail * MACB_DESC_ADDR_INTERVAL;
+
+ for (nb_idx = 0; nb_idx < nb_xmit_vec; tx_tail += MACB_DESCS_PER_LOOP,
+ nb_idx += MACB_DESCS_PER_LOOP,
+ txdesc += MACB_DESCS_PER_LOOP * MACB_DESC_ADDR_INTERVAL) {
+ nb_segs_v = vset_lane_u16(tx_pkts[nb_tx]->nb_segs, nb_segs_v, 0);
+ nb_segs_v = vset_lane_u16(tx_pkts[nb_tx + 1]->nb_segs, nb_segs_v, 1);
+ nb_segs_v = vset_lane_u16(tx_pkts[nb_tx + 2]->nb_segs, nb_segs_v, 2);
+ nb_segs_v = vset_lane_u16(tx_pkts[nb_tx + 3]->nb_segs, nb_segs_v, 3);
+ if (vmaxv_u16(nb_segs_v) > 1) {
+ queue->tx_tail = macb_tx_ring_wrap(bp, tx_tail);
+ nb_txok = eth_macb_xmit_pkts(queue, &tx_pkts[nb_tx], nb_pkts);
+ nb_tx += nb_txok;
+ goto out;
+ }
+
+ if (likely(txe[nb_tx].mbuf != NULL))
+ rte_pktmbuf_free_seg(txe[nb_tx].mbuf);
+ if (likely(txe[nb_tx + 1].mbuf != NULL))
+ rte_pktmbuf_free_seg(txe[nb_tx + 1].mbuf);
+ if (likely(txe[nb_tx + 2].mbuf != NULL))
+ rte_pktmbuf_free_seg(txe[nb_tx + 2].mbuf);
+ if (likely(txe[nb_tx + 3].mbuf != NULL))
+ rte_pktmbuf_free_seg(txe[nb_tx + 3].mbuf);
+
+ mbp1 = vld1q_u64((uint64_t *)&tx_pkts[nb_tx]);
+ mbp2 = vld1q_u64((uint64_t *)&tx_pkts[nb_tx + 2]);
+ vst1q_u64((uint64_t *)&txe[nb_tx], mbp1);
+ vst1q_u64((uint64_t *)&txe[nb_tx + 2], mbp2);
+
+ queue->stats.tx_bytes +=
+ tx_pkts[nb_tx]->pkt_len + tx_pkts[nb_tx + 1]->pkt_len +
+ tx_pkts[nb_tx + 2]->pkt_len + tx_pkts[nb_tx + 3]->pkt_len;
+ macb_set_txdesc(queue, txdesc, &tx_pkts[nb_tx], tx_tail);
+ queue->stats.tx_packets += MACB_DESCS_PER_LOOP;
+ nb_tx += MACB_DESCS_PER_LOOP;
+ nb_pkts = nb_pkts - MACB_DESCS_PER_LOOP;
+ }
+
+ tx_tail = macb_tx_ring_wrap(bp, tx_tail);
+ queue->tx_tail = tx_tail;
+ if (nb_pkts > 0)
+ nb_tx += eth_macb_xmit_pkts(queue, &tx_pkts[nb_tx], nb_pkts);
+ else
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+
+out:
+ return nb_tx;
+}
+
+uint16_t eth_macb_xmit_pkts_vec(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts)
+{
+ struct macb_tx_queue *queue;
+ struct macb *bp;
+ uint16_t nb_free;
+ uint16_t nb_total_free;
+ uint32_t tx_head, tx_tail;
+ uint16_t nb_tx, nb_total_tx = 0;
+
+ queue = (struct macb_tx_queue *)tx_queue;
+ bp = queue->bp;
+
+ macb_reclaim_txd(queue);
+
+retry:
+ tx_head = queue->tx_head;
+ tx_tail = queue->tx_tail;
+
+ if (unlikely(tx_head == tx_tail))
+ nb_total_free = bp->tx_ring_size - 1;
+ else if (tx_head > tx_tail)
+ nb_total_free = tx_head - tx_tail - 1;
+ else
+ nb_total_free = bp->tx_ring_size - (tx_tail - tx_head) - 1;
+
+ nb_pkts = RTE_MIN(nb_total_free, nb_pkts);
+ nb_free = bp->tx_ring_size - tx_tail;
+
+ if (nb_pkts > nb_free && nb_free > 0) {
+ nb_tx = macb_xmit_pkts_vec(queue, tx_pkts, nb_free);
+ nb_total_tx += nb_tx;
+ nb_pkts -= nb_tx;
+ tx_pkts += nb_tx;
+ goto retry;
+ }
+ if (nb_pkts > 0)
+ nb_total_tx += macb_xmit_pkts_vec(queue, tx_pkts, nb_pkts);
+
+ return nb_total_tx;
+}
diff --git a/drivers/net/macb/meson.build b/drivers/net/macb/meson.build
new file mode 100644
index 0000000..dbedd86
--- /dev/null
+++ b/drivers/net/macb/meson.build
@@ -0,0 +1,24 @@
+# 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
+
+#allow_experimental_apis = true
+
+subdir('base')
+objs = [base_objs]
+
+sources = files(
+ 'macb_ethdev.c',
+ 'macb_rxtx.c',
+ )
+
+if arch_subdir == 'arm'
+ sources += files('macb_rxtx_vec_neon.c')
+endif
+
+includes += include_directories('base')
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index fb6d34b..44f1e74 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -35,6 +35,7 @@ drivers = [
'ionic',
'ipn3ke',
'ixgbe',
+ 'macb',
'mana',
'memif',
'mlx4',
--
2.7.4
next reply other threads:[~2024-11-01 10:07 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-01 10:07 liwencheng [this message]
2024-11-01 10:07 ` [PATCH v1 2/2] /usertools/dpdk-devbind:add the binding and unbinding of platform device liwencheng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1730455640-1084345-1-git-send-email-liwencheng@phytium.com.cn \
--to=liwencheng@phytium.com.cn \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).