The branch main has been updated by kgalazka:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=dea5f973d0c8d29a79b433283d0a2de8f4615957

commit dea5f973d0c8d29a79b433283d0a2de8f4615957
Author:     Bhosale, Yogeshnull <nullyogesh.bhos...@intel.com>
AuthorDate: 2025-08-19 14:19:07 +0000
Commit:     Krzysztof Galazka <kgala...@freebsd.org>
CommitDate: 2025-08-19 15:09:33 +0000

    ix/ixv: Add support for new Intel Ethernet E610 family devices
    
    This is part 1 of the support for the new Intel Ethernet E610 family of 
devices.
    
    Introduce new PCI device IDs:
    • 57AE: Intel(R) E610 (Backplane)
    • 57AF: Intel(R) E610 (SFP)
    • 57B0: Intel(R) E610 (10 GbE)
    • 57B1: Intel(R) E610 (2.5 GbE)
    • 57B2: Intel(R) E610 (SGMII)
    
    Key updates for E610 family:
    • Firmware manages Link and PHY
    • Implement new CSR-based Admin Command Interface (ACI) for SW-FW 
interaction
    • Tested exclusively for x64 operating systems on E610-XT2/XT4 (10G) and 
E610-IT4 (2.5G)
    • Enable link speeds above 1G: 2.5G, 5G and 10G
    • NVM Recovery Mode and Rollback support
    
    Signed-off-by: Yogesh Bhosale yogesh.bhos...@intel.com
    Co-developed-by: Krzysztof Galazka krzysztof.gala...@intel.com
    
    Approved by:    kbowling (mentor), erj (mentor)
    Tested by:      gowtham.kumar.ks_intel.com
    Sponsored by:   Intel Corporation
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D50067
---
 sys/conf/files                  |    2 +
 sys/dev/ixgbe/if_ix.c           |  231 +-
 sys/dev/ixgbe/if_ixv.c          |    6 +
 sys/dev/ixgbe/ixgbe.h           |   11 +
 sys/dev/ixgbe/ixgbe_api.c       |   16 +
 sys/dev/ixgbe/ixgbe_api.h       |    1 +
 sys/dev/ixgbe/ixgbe_common.c    |   25 +-
 sys/dev/ixgbe/ixgbe_e610.c      | 5567 +++++++++++++++++++++++++++++++++++++++
 sys/dev/ixgbe/ixgbe_e610.h      |  224 ++
 sys/dev/ixgbe/ixgbe_osdep.c     |   26 +
 sys/dev/ixgbe/ixgbe_osdep.h     |   31 +
 sys/dev/ixgbe/ixgbe_type.h      |   69 +-
 sys/dev/ixgbe/ixgbe_type_e610.h | 2278 ++++++++++++++++
 sys/dev/ixgbe/ixgbe_vf.c        |    3 +-
 sys/modules/ix/Makefile         |    2 +-
 sys/modules/ixv/Makefile        |    2 +-
 16 files changed, 8458 insertions(+), 36 deletions(-)

diff --git a/sys/conf/files b/sys/conf/files
index 35318dbc8367..8bb14bd3d953 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2281,6 +2281,8 @@ dev/ixgbe/ixgbe_x540.c            optional ix inet | ixv 
inet \
        compile-with "${NORMAL_C} -I$S/dev/ixgbe"
 dev/ixgbe/ixgbe_x550.c         optional ix inet | ixv inet \
        compile-with "${NORMAL_C} -I$S/dev/ixgbe"
+dev/ixgbe/ixgbe_e610.c         optional ix inet | ixv inet \
+       compile-with "${NORMAL_C} -I$S/dev/ixgbe"
 dev/ixgbe/ixgbe_dcb.c          optional ix inet | ixv inet \
        compile-with "${NORMAL_C} -I$S/dev/ixgbe"
 dev/ixgbe/ixgbe_dcb_82598.c    optional ix inet | ixv inet \
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 959afa79e7da..73c0fd1ab16f 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -45,7 +45,7 @@
 /************************************************************************
  * Driver version
  ************************************************************************/
-static const char ixgbe_driver_version[] = "4.0.1-k";
+static const char ixgbe_driver_version[] = "5.0.1-k";
 
 /************************************************************************
  * PCI Device ID Table
@@ -144,6 +144,16 @@ static const pci_vendor_info_t ixgbe_vendor_info_array[] =
     "Intel(R) X540-T2 (Bypass)"),
        PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BYPASS,
     "Intel(R) X520 82599 (Bypass)"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_BACKPLANE,
+     "Intel(R) E610 (Backplane)"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_SFP,
+     "Intel(R) E610 (SFP)"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_2_5G_T,
+     "Intel(R) E610 (2.5 GbE)"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_10G_T,
+     "Intel(R) E610 (10 GbE)"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_SGMII,
+     "Intel(R) E610 (SGMII)"),
        /* required last entry */
        PVID_END
 };
@@ -253,6 +263,10 @@ static int  
ixgbe_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS);
 static void ixgbe_handle_msf(void *);
 static void ixgbe_handle_mod(void *);
 static void ixgbe_handle_phy(void *);
+static void ixgbe_handle_fw_event(void *);
+
+static int ixgbe_enable_lse(struct ixgbe_softc *sc);
+static int ixgbe_disable_lse(struct ixgbe_softc *sc);
 
 /************************************************************************
  *  FreeBSD Device Interface Entry Points
@@ -621,6 +635,7 @@ ixgbe_initialize_rss_mapping(struct ixgbe_softc *sc)
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
+       case ixgbe_mac_E610:
                table_size = 512;
                break;
        default:
@@ -902,6 +917,32 @@ ixgbe_initialize_transmit_units(if_ctx_t ctx)
 
 } /* ixgbe_initialize_transmit_units */
 
+static int
+ixgbe_check_fw_api_version(struct ixgbe_softc *sc)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       if (hw->api_maj_ver > IXGBE_FW_API_VER_MAJOR) {
+               device_printf(sc->dev,
+                   "The driver for the device stopped because the NVM "
+                   "image is newer than expected. You must install the "
+                   "most recent version of the network driver.\n");
+               return (EOPNOTSUPP);
+       } else if (hw->api_maj_ver == IXGBE_FW_API_VER_MAJOR &&
+                  hw->api_min_ver > (IXGBE_FW_API_VER_MINOR + 2)) {
+               device_printf(sc->dev,
+                   "The driver for the device detected a newer version of "
+                   "the NVM image than expected. Please install the most "
+                   "recent version of the network driver.\n");
+       } else if (hw->api_maj_ver < IXGBE_FW_API_VER_MAJOR ||
+                  hw->api_min_ver < IXGBE_FW_API_VER_MINOR - 2) {
+               device_printf(sc->dev,
+                       "The driver for the device detected an older version "
+                       "of the NVM image than expected. "
+                       "Please update the NVM image.\n");
+       }
+       return (0);
+}
+
 /************************************************************************
  * ixgbe_register
  ************************************************************************/
@@ -970,6 +1011,9 @@ ixgbe_if_attach_pre(if_ctx_t ctx)
                goto err_pci;
        }
 
+       if (hw->mac.type == ixgbe_mac_E610)
+               ixgbe_init_aci(hw);
+
        if (hw->mac.ops.fw_recovery_mode &&
            hw->mac.ops.fw_recovery_mode(hw)) {
                device_printf(dev,
@@ -1058,6 +1102,12 @@ ixgbe_if_attach_pre(if_ctx_t ctx)
                break;
        }
 
+       /* Check the FW API version */
+       if (hw->mac.type == ixgbe_mac_E610 && ixgbe_check_fw_api_version(sc)) {
+               error = EIO;
+               goto err_pci;
+       }
+
        /* Most of the iflib initialization... */
 
        iflib_set_mac(ctx, hw->mac.addr);
@@ -1111,6 +1161,9 @@ err_pci:
        IXGBE_WRITE_REG(&sc->hw, IXGBE_CTRL_EXT, ctrl_ext);
        ixgbe_free_pci_resources(ctx);
 
+       if (hw->mac.type == ixgbe_mac_E610)
+               ixgbe_shutdown_aci(hw);
+
        return (error);
 } /* ixgbe_if_attach_pre */
 
@@ -1358,6 +1411,10 @@ ixgbe_add_media_types(if_ctx_t ctx)
        /* Media types with matching FreeBSD media defines */
        if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T)
                ifmedia_add(sc->media, IFM_ETHER | IFM_10G_T, 0, NULL);
+       if (layer & IXGBE_PHYSICAL_LAYER_5000BASE_T)
+               ifmedia_add(sc->media, IFM_ETHER | IFM_5000_T, 0, NULL);
+       if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_T)
+               ifmedia_add(sc->media, IFM_ETHER | IFM_2500_T, 0, NULL);
        if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T)
                ifmedia_add(sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
        if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX)
@@ -1459,6 +1516,7 @@ ixgbe_is_sfp(struct ixgbe_hw *hw)
                }
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
+       case ixgbe_mac_E610:
                if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber)
                        return (true);
                return (false);
@@ -1525,6 +1583,15 @@ ixgbe_config_link(if_ctx_t ctx)
                            IXGBE_LINK_SPEED_5GB_FULL);
                }
 
+               if (hw->mac.type == ixgbe_mac_E610) {
+                       hw->phy.ops.init(hw);
+                       err = ixgbe_enable_lse(sc);
+                       if (err)
+                               device_printf(sc->dev,
+                                   "Failed to enable Link Status Event, "
+                                   "error: %d", err);
+               }
+
                if (hw->mac.ops.setup_link)
                        err = hw->mac.ops.setup_link(hw, autoneg,
                            sc->link_up);
@@ -2158,14 +2225,15 @@ get_parent_info:
        ixgbe_set_pci_config_data_generic(hw, link);
 
 display:
-       device_printf(dev, "PCI Express Bus: Speed %s %s\n",
-           ((hw->bus.speed == ixgbe_bus_speed_8000)    ? "8.0GT/s"  :
+       device_printf(dev, "PCI Express Bus: Speed %s Width %s\n",
+           ((hw->bus.speed == ixgbe_bus_speed_16000)   ? "16.0GT/s" :
+            (hw->bus.speed == ixgbe_bus_speed_8000)    ? "8.0GT/s"  :
             (hw->bus.speed == ixgbe_bus_speed_5000)    ? "5.0GT/s"  :
             (hw->bus.speed == ixgbe_bus_speed_2500)    ? "2.5GT/s"  :
             "Unknown"),
-           ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
-            (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
-            (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
+           ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "x8" :
+            (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "x4" :
+            (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "x1" :
             "Unknown"));
 
        if (bus_info_valid) {
@@ -2372,14 +2440,17 @@ ixgbe_if_media_status(if_ctx_t ctx, struct ifmediareq * 
ifmr)
        ifmr->ifm_status |= IFM_ACTIVE;
        layer = sc->phy_layer;
 
-       if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T ||
-           layer & IXGBE_PHYSICAL_LAYER_1000BASE_T ||
-           layer & IXGBE_PHYSICAL_LAYER_100BASE_TX ||
-           layer & IXGBE_PHYSICAL_LAYER_10BASE_T)
+       if (layer & IXGBE_PHYSICAL_LAYERS_BASE_T_ALL)
                switch (sc->link_speed) {
                case IXGBE_LINK_SPEED_10GB_FULL:
                        ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
                        break;
+               case IXGBE_LINK_SPEED_5GB_FULL:
+                       ifmr->ifm_active |= IFM_5000_T | IFM_FDX;
+                       break;
+               case IXGBE_LINK_SPEED_2_5GB_FULL:
+                       ifmr->ifm_active |= IFM_2500_T | IFM_FDX;
+                       break;
                case IXGBE_LINK_SPEED_1GB_FULL:
                        ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
                        break;
@@ -2390,15 +2461,6 @@ ixgbe_if_media_status(if_ctx_t ctx, struct ifmediareq * 
ifmr)
                        ifmr->ifm_active |= IFM_10_T | IFM_FDX;
                        break;
                }
-       if (hw->mac.type == ixgbe_mac_X550)
-               switch (sc->link_speed) {
-               case IXGBE_LINK_SPEED_5GB_FULL:
-                       ifmr->ifm_active |= IFM_5000_T | IFM_FDX;
-                       break;
-               case IXGBE_LINK_SPEED_2_5GB_FULL:
-                       ifmr->ifm_active |= IFM_2500_T | IFM_FDX;
-                       break;
-               }
        if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU ||
            layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA)
                switch (sc->link_speed) {
@@ -2676,6 +2738,11 @@ ixgbe_msix_link(void *arg)
                sc->task_requests |= IXGBE_REQUEST_TASK_LSC;
        }
 
+       if (eicr & IXGBE_EICR_FW_EVENT) {
+               IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FW_EVENT);
+               sc->task_requests |= IXGBE_REQUEST_TASK_FWEVENT;
+       }
+
        if (sc->hw.mac.type != ixgbe_mac_82598EB) {
                if ((sc->feat_en & IXGBE_FEATURE_FDIR) &&
                    (eicr & IXGBE_EICR_FLOW_DIR)) {
@@ -2734,11 +2801,16 @@ ixgbe_msix_link(void *arg)
 
                /* Check for VF message */
                if ((sc->feat_en & IXGBE_FEATURE_SRIOV) &&
-                   (eicr & IXGBE_EICR_MAILBOX))
+                   (eicr & IXGBE_EICR_MAILBOX)) {
                        sc->task_requests |= IXGBE_REQUEST_TASK_MBX;
+               }
        }
 
-       if (ixgbe_is_sfp(hw)) {
+       /*
+        * On E610, the firmware handles PHY configuration, so
+        * there is no need to perform any SFP-specific tasks.
+        */
+       if (hw->mac.type != ixgbe_mac_E610 && ixgbe_is_sfp(hw)) {
                /* Pluggable optics-related interrupt */
                if (hw->mac.type >= ixgbe_mac_X540)
                        eicr_mask = IXGBE_EICR_GPI_SDP0_X540;
@@ -2985,7 +3057,13 @@ ixgbe_if_detach(if_ctx_t ctx)
 
        callout_drain(&sc->fw_mode_timer);
 
+       if (sc->hw.mac.type == ixgbe_mac_E610) {
+               ixgbe_disable_lse(sc);
+               ixgbe_shutdown_aci(&sc->hw);
+       }
+
        ixgbe_free_pci_resources(ctx);
+
        free(sc->mta, M_IXGBE);
 
        return (0);
@@ -3404,6 +3482,7 @@ ixgbe_set_ivar(struct ixgbe_softc *sc, u8 entry, u8 
vector, s8 type)
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
+       case ixgbe_mac_E610:
                if (type == -1) { /* MISC IVAR */
                        index = (entry & 1) * 8;
                        ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
@@ -3825,6 +3904,96 @@ ixgbe_handle_phy(void *context)
                    "Error handling LASI interrupt: %d\n", error);
 } /* ixgbe_handle_phy */
 
+/************************************************************************
+ * ixgbe_enable_lse - enable link status events
+ *
+ *   Sets mask and enables link status events
+ ************************************************************************/
+s32 ixgbe_enable_lse(struct ixgbe_softc *sc)
+{
+       s32 error;
+
+       u16 mask = ~((u16)(IXGBE_ACI_LINK_EVENT_UPDOWN |
+                          IXGBE_ACI_LINK_EVENT_MEDIA_NA |
+                          IXGBE_ACI_LINK_EVENT_MODULE_QUAL_FAIL |
+                          IXGBE_ACI_LINK_EVENT_PHY_FW_LOAD_FAIL));
+
+       error = ixgbe_configure_lse(&sc->hw, TRUE, mask);
+       if (error)
+               return (error);
+
+       sc->lse_mask = mask;
+       return (IXGBE_SUCCESS);
+} /* ixgbe_enable_lse */
+
+/************************************************************************
+ * ixgbe_disable_lse - disable link status events
+ ************************************************************************/
+s32 ixgbe_disable_lse(struct ixgbe_softc *sc)
+{
+       s32 error;
+
+       error = ixgbe_configure_lse(&sc->hw, false, sc->lse_mask);
+       if (error)
+               return (error);
+
+       sc->lse_mask = 0;
+       return (IXGBE_SUCCESS);
+} /* ixgbe_disable_lse */
+
+/************************************************************************
+ * ixgbe_handle_fw_event - Tasklet for MSI-X Link Status Event interrupts
+ ************************************************************************/
+static void
+ixgbe_handle_fw_event(void *context)
+{
+       if_ctx_t ctx = context;
+       struct ixgbe_softc *sc = iflib_get_softc(ctx);
+       struct ixgbe_hw *hw = &sc->hw;
+       struct ixgbe_aci_event event;
+       bool pending = false;
+       s32 error;
+
+       event.buf_len = IXGBE_ACI_MAX_BUFFER_SIZE;
+       event.msg_buf = malloc(event.buf_len, M_IXGBE, M_ZERO | M_NOWAIT);
+       if (!event.msg_buf) {
+               device_printf(sc->dev, "Can not allocate buffer for "
+                   "event message\n");
+               return;
+       }
+
+       do {
+               error = ixgbe_aci_get_event(hw, &event, &pending);
+               if (error) {
+                       device_printf(sc->dev, "Error getting event from "
+                           "FW:%d\n", error);
+                       break;
+               }
+
+               switch (le16toh(event.desc.opcode)) {
+               case ixgbe_aci_opc_get_link_status:
+                       sc->task_requests |= IXGBE_REQUEST_TASK_LSC;
+                       break;
+
+               case ixgbe_aci_opc_temp_tca_event:
+                       if (hw->adapter_stopped == FALSE)
+                               ixgbe_if_stop(ctx);
+                       device_printf(sc->dev,
+                           "CRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n");
+                       device_printf(sc->dev, "System shutdown required!\n");
+                       break;
+
+               default:
+                       device_printf(sc->dev,
+                           "Unknown FW event captured, opcode=0x%04X\n",
+                           le16toh(event.desc.opcode));
+                       break;
+               }
+       } while (pending);
+
+       free(event.msg_buf, M_IXGBE);
+} /* ixgbe_handle_fw_event */
+
 /************************************************************************
  * ixgbe_if_stop - Stop the hardware
  *
@@ -3899,6 +4068,8 @@ ixgbe_if_update_admin_status(if_ctx_t ctx)
        }
 
        /* Handle task requests from msix_link() */
+       if (sc->task_requests & IXGBE_REQUEST_TASK_FWEVENT)
+               ixgbe_handle_fw_event(ctx);
        if (sc->task_requests & IXGBE_REQUEST_TASK_MOD)
                ixgbe_handle_mod(ctx);
        if (sc->task_requests & IXGBE_REQUEST_TASK_MSF)
@@ -3986,6 +4157,9 @@ ixgbe_if_enable_intr(if_ctx_t ctx)
                        mask |= IXGBE_EICR_GPI_SDP0_X540;
                mask |= IXGBE_EIMS_ECC;
                break;
+       case ixgbe_mac_E610:
+               mask |= IXGBE_EIMS_FW_EVENT;
+               break;
        default:
                break;
        }
@@ -4008,6 +4182,7 @@ ixgbe_if_enable_intr(if_ctx_t ctx)
                /* Don't autoclear Link */
                mask &= ~IXGBE_EIMS_OTHER;
                mask &= ~IXGBE_EIMS_LSC;
+               mask &= ~IXGBE_EIMS_FW_EVENT;
                if (sc->feat_cap & IXGBE_FEATURE_SRIOV)
                        mask &= ~IXGBE_EIMS_MAILBOX;
                IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
@@ -4026,7 +4201,7 @@ ixgbe_if_enable_intr(if_ctx_t ctx)
 } /* ixgbe_if_enable_intr */
 
 /************************************************************************
- * ixgbe_disable_intr
+ * ixgbe_if_disable_intr
  ************************************************************************/
 static void
 ixgbe_if_disable_intr(if_ctx_t ctx)
@@ -4176,8 +4351,9 @@ ixgbe_intr(void *arg)
 
        /* External PHY interrupt */
        if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
-           (eicr & IXGBE_EICR_GPI_SDP0_X540))
+           (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
                sc->task_requests |= IXGBE_REQUEST_TASK_PHY;
+       }
 
        return (FILTER_SCHEDULE_THREAD);
 } /* ixgbe_intr */
@@ -4219,7 +4395,7 @@ ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS)
        int error, fc;
 
        sc = (struct ixgbe_softc *)arg1;
-       fc = sc->hw.fc.current_mode;
+       fc = sc->hw.fc.requested_mode;
 
        error = sysctl_handle_int(oidp, &fc, 0, req);
        if ((error) || (req->newptr == NULL))
@@ -4248,12 +4424,10 @@ ixgbe_set_flowcntl(struct ixgbe_softc *sc, int fc)
        case ixgbe_fc_rx_pause:
        case ixgbe_fc_tx_pause:
        case ixgbe_fc_full:
-               sc->hw.fc.requested_mode = fc;
                if (sc->num_rx_queues > 1)
                        ixgbe_disable_rx_drop(sc);
                break;
        case ixgbe_fc_none:
-               sc->hw.fc.requested_mode = ixgbe_fc_none;
                if (sc->num_rx_queues > 1)
                        ixgbe_enable_rx_drop(sc);
                break;
@@ -4261,6 +4435,8 @@ ixgbe_set_flowcntl(struct ixgbe_softc *sc, int fc)
                return (EINVAL);
        }
 
+       sc->hw.fc.requested_mode = fc;
+
        /* Don't autoneg if forcing a value */
        sc->hw.fc.disable_fc_autoneg = true;
        ixgbe_fc_enable(&sc->hw);
@@ -4978,6 +5154,9 @@ ixgbe_init_device_features(struct ixgbe_softc *sc)
                if (sc->hw.device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP)
                        sc->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
                break;
+       case ixgbe_mac_E610:
+               sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
+               break;
        default:
                break;
        }
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 54b2c8c1dd68..8a1c1aae041d 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -68,6 +68,8 @@ static const pci_vendor_info_t ixv_vendor_info_array[] =
            "Intel(R) X552 Virtual Function"),
        PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF,
            "Intel(R) X553 Virtual Function"),
+       PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_E610_VF,
+           "Intel(R) E610 Virtual Function"),
        /* required last entry */
        PVID_END
 };
@@ -1020,6 +1022,9 @@ ixv_identify_hardware(if_ctx_t ctx)
        case IXGBE_DEV_ID_X550EM_A_VF:
                hw->mac.type = ixgbe_mac_X550EM_a_vf;
                break;
+       case IXGBE_DEV_ID_E610_VF:
+               hw->mac.type = ixgbe_mac_E610_vf;
+               break;
        default:
                device_printf(dev, "unknown mac type\n");
                hw->mac.type = ixgbe_mac_unknown;
@@ -1955,6 +1960,7 @@ ixv_init_device_features(struct ixgbe_softc *sc)
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
        case ixgbe_mac_X550EM_a_vf:
+       case ixgbe_mac_E610_vf:
                sc->feat_cap |= IXGBE_FEATURE_NEEDS_CTXD;
                sc->feat_cap |= IXGBE_FEATURE_RSS;
                break;
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 341d4ebfcebc..844064bf8543 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -86,6 +86,7 @@
 #include "ixgbe_phy.h"
 #include "ixgbe_vf.h"
 #include "ixgbe_features.h"
+#include "ixgbe_e610.h"
 
 /* Tunables */
 
@@ -195,6 +196,15 @@
                            CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \
                            CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP)
 
+/* All BASE-T Physical layers */
+#define IXGBE_PHYSICAL_LAYERS_BASE_T_ALL \
+       (IXGBE_PHYSICAL_LAYER_10GBASE_T |\
+        IXGBE_PHYSICAL_LAYER_5000BASE_T |\
+        IXGBE_PHYSICAL_LAYER_2500BASE_T |\
+        IXGBE_PHYSICAL_LAYER_1000BASE_T |\
+        IXGBE_PHYSICAL_LAYER_100BASE_TX |\
+        IXGBE_PHYSICAL_LAYER_10BASE_T)
+
 #define IXGBE_CAPS (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | IFCAP_TSO | \
                    IFCAP_LRO | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO | \
                    IFCAP_VLAN_HWCSUM | IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU | \
@@ -464,6 +474,7 @@ struct ixgbe_softc {
        /* Feature capable/enabled flags.  See ixgbe_features.h */
        u32                     feat_cap;
        u32                     feat_en;
+       u16                     lse_mask;
 };
 
 /* Precision Time Sync (IEEE 1588) defines */
diff --git a/sys/dev/ixgbe/ixgbe_api.c b/sys/dev/ixgbe/ixgbe_api.c
index 4c50f10ed92e..f11f52a646e4 100644
--- a/sys/dev/ixgbe/ixgbe_api.c
+++ b/sys/dev/ixgbe/ixgbe_api.c
@@ -112,11 +112,15 @@ s32 ixgbe_init_shared_code(struct ixgbe_hw *hw)
        case ixgbe_mac_X550EM_a:
                status = ixgbe_init_ops_X550EM_a(hw);
                break;
+       case ixgbe_mac_E610:
+               status = ixgbe_init_ops_E610(hw);
+               break;
        case ixgbe_mac_82599_vf:
        case ixgbe_mac_X540_vf:
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
        case ixgbe_mac_X550EM_a_vf:
+       case ixgbe_mac_E610_vf:
                status = ixgbe_init_ops_vf(hw);
                break;
        default:
@@ -240,6 +244,18 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *hw)
                hw->mac.type = ixgbe_mac_X550EM_a_vf;
                hw->mvals = ixgbe_mvals_X550EM_a;
                break;
+       case IXGBE_DEV_ID_E610_BACKPLANE:
+       case IXGBE_DEV_ID_E610_SFP:
+       case IXGBE_DEV_ID_E610_10G_T:
+       case IXGBE_DEV_ID_E610_2_5G_T:
+       case IXGBE_DEV_ID_E610_SGMII:
+               hw->mac.type = ixgbe_mac_E610;
+               hw->mvals = ixgbe_mvals_X550EM_a;
+               break;
+       case IXGBE_DEV_ID_E610_VF:
+               hw->mac.type = ixgbe_mac_E610_vf;
+               hw->mvals = ixgbe_mvals_X550EM_a;
+               break;
        default:
                ret_val = IXGBE_ERR_DEVICE_NOT_SUPPORTED;
                ERROR_REPORT2(IXGBE_ERROR_UNSUPPORTED,
diff --git a/sys/dev/ixgbe/ixgbe_api.h b/sys/dev/ixgbe/ixgbe_api.h
index b81510dacb95..2b4cec8d110e 100644
--- a/sys/dev/ixgbe/ixgbe_api.h
+++ b/sys/dev/ixgbe/ixgbe_api.h
@@ -48,6 +48,7 @@ extern s32 ixgbe_init_ops_X550(struct ixgbe_hw *hw);
 extern s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw);
 extern s32 ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw);
 extern s32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw);
+extern s32 ixgbe_init_ops_E610(struct ixgbe_hw *hw);
 extern s32 ixgbe_init_ops_vf(struct ixgbe_hw *hw);
 
 s32 ixgbe_set_mac_type(struct ixgbe_hw *hw);
diff --git a/sys/dev/ixgbe/ixgbe_common.c b/sys/dev/ixgbe/ixgbe_common.c
index df7ab90e72ab..bff022585a03 100644
--- a/sys/dev/ixgbe/ixgbe_common.c
+++ b/sys/dev/ixgbe/ixgbe_common.c
@@ -178,6 +178,7 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
                case IXGBE_DEV_ID_X550EM_A_SFP_N:
                case IXGBE_DEV_ID_X550EM_A_QSFP:
                case IXGBE_DEV_ID_X550EM_A_QSFP_N:
+               case IXGBE_DEV_ID_E610_SFP:
                        supported = false;
                        break;
                default:
@@ -210,6 +211,8 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
                case IXGBE_DEV_ID_X550EM_A_10G_T:
                case IXGBE_DEV_ID_X550EM_A_1G_T:
                case IXGBE_DEV_ID_X550EM_A_1G_T_L:
+               case IXGBE_DEV_ID_E610_10G_T:
+               case IXGBE_DEV_ID_E610_2_5G_T:
                        supported = true;
                        break;
                default:
@@ -616,7 +619,8 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
                }
        }
 
-       if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X540) {
+       if (hw->mac.type == ixgbe_mac_X540 ||
+           hw->mac.type == ixgbe_mac_X550) {
                if (hw->phy.id == 0)
                        ixgbe_identify_phy(hw);
                hw->phy.ops.read_reg(hw, IXGBE_PCRC8ECL,
@@ -1037,6 +1041,9 @@ void ixgbe_set_pci_config_data_generic(struct ixgbe_hw 
*hw, u16 link_status)
        case IXGBE_PCI_LINK_SPEED_8000:
                hw->bus.speed = ixgbe_bus_speed_8000;
                break;
+       case IXGBE_PCI_LINK_SPEED_16000:
+               hw->bus.speed = ixgbe_bus_speed_16000;
+               break;
        default:
                hw->bus.speed = ixgbe_bus_speed_unknown;
                break;
@@ -1059,7 +1066,9 @@ s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
        DEBUGFUNC("ixgbe_get_bus_info_generic");
 
        /* Get the negotiated link width and speed from PCI config space */
-       link_status = IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_LINK_STATUS);
+       link_status = IXGBE_READ_PCIE_WORD(hw, hw->mac.type == ixgbe_mac_E610 ?
+                                          IXGBE_PCI_LINK_STATUS_E610 :
+                                          IXGBE_PCI_LINK_STATUS);
 
        ixgbe_set_pci_config_data_generic(hw, link_status);
 
@@ -1878,7 +1887,6 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
 
        DEBUGFUNC("ixgbe_get_eeprom_semaphore");
 
-
        /* Get SMBI software semaphore between device drivers first */
        for (i = 0; i < timeout; i++) {
                /*
@@ -3363,7 +3371,6 @@ s32 ixgbe_disable_sec_rx_path_generic(struct ixgbe_hw *hw)
 
        DEBUGFUNC("ixgbe_disable_sec_rx_path_generic");
 
-
        secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
        secrxreg |= IXGBE_SECRXCTRL_RX_DIS;
        IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, secrxreg);
@@ -3692,6 +3699,10 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw 
*hw)
                pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS;
                max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
                break;
+       case ixgbe_mac_E610:
+               pcie_offset = IXGBE_PCIE_MSIX_E610_CAPS;
+               max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
+               break;
        default:
                return msix_count;
        }
@@ -4139,7 +4150,6 @@ s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw)
        return IXGBE_SUCCESS;
 }
 
-
 /**
  * ixgbe_toggle_txdctl_generic - Toggle VF's queues
  * @hw: pointer to hardware structure
@@ -4323,7 +4333,8 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, 
ixgbe_link_speed *speed,
                break;
        case IXGBE_LINKS_SPEED_100_82599:
                *speed = IXGBE_LINK_SPEED_100_FULL;
-               if (hw->mac.type == ixgbe_mac_X550) {
+               if (hw->mac.type == ixgbe_mac_X550 ||
+                   hw->mac.type == ixgbe_mac_E610) {
                        if (links_reg & IXGBE_LINKS_SPEED_NON_STD)
                                *speed = IXGBE_LINK_SPEED_5GB_FULL;
                }
@@ -5494,6 +5505,7 @@ void ixgbe_get_nvm_version(struct ixgbe_hw *hw,
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
+       case ixgbe_mac_E610:
                /* version of eeprom section */
                if (ixgbe_read_eeprom(hw, NVM_EEP_OFFSET_X540, &word))
                        word = NVM_VER_INVALID;
@@ -5512,6 +5524,7 @@ void ixgbe_get_nvm_version(struct ixgbe_hw *hw,
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_X550EM_a:
+       case ixgbe_mac_E610:
                /* intel phy firmware version */
                if (ixgbe_read_eeprom(hw, NVM_EEP_PHY_OFF_X540, &word))
                        word = NVM_VER_INVALID;
diff --git a/sys/dev/ixgbe/ixgbe_e610.c b/sys/dev/ixgbe/ixgbe_e610.c
new file mode 100644
index 000000000000..95c6dca416c6
--- /dev/null
+++ b/sys/dev/ixgbe/ixgbe_e610.c
@@ -0,0 +1,5567 @@
+/******************************************************************************
+  SPDX-License-Identifier: BSD-3-Clause
+
+  Copyright (c) 2025, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include "ixgbe_type.h"
+#include "ixgbe_e610.h"
+#include "ixgbe_x550.h"
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+#include "ixgbe_api.h"
+
+/**
+ * ixgbe_init_aci - initialization routine for Admin Command Interface
+ * @hw: pointer to the hardware structure
+ *
+ * Initialize the ACI lock.
+ */
+void ixgbe_init_aci(struct ixgbe_hw *hw)
+{
+       ixgbe_init_lock(&hw->aci.lock);
+}
+
+/**
+ * ixgbe_shutdown_aci - shutdown routine for Admin Command Interface
+ * @hw: pointer to the hardware structure
+ *
+ * Destroy the ACI lock.
+ */
+void ixgbe_shutdown_aci(struct ixgbe_hw *hw)
+{
+       ixgbe_destroy_lock(&hw->aci.lock);
+}
+
+/**
+ * ixgbe_should_retry_aci_send_cmd_execute - decide if ACI command should
+ * be resent
+ * @opcode: ACI opcode
+ *
+ * Check if ACI command should be sent again depending on the provided opcode.
+ *
+ * Return: true if the sending command routine should be repeated,
+ * otherwise false.
+ */
+static bool ixgbe_should_retry_aci_send_cmd_execute(u16 opcode)
+{
+       switch (opcode) {
+       case ixgbe_aci_opc_disable_rxen:
+       case ixgbe_aci_opc_get_phy_caps:
+       case ixgbe_aci_opc_get_link_status:
+       case ixgbe_aci_opc_get_link_topo:
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * ixgbe_aci_send_cmd_execute - execute sending FW Admin Command to FW Admin
+ * Command Interface
+ * @hw: pointer to the HW struct
+ * @desc: descriptor describing the command
+ * @buf: buffer to use for indirect commands (NULL for direct commands)
+ * @buf_size: size of buffer for indirect commands (0 for direct commands)
+ *
+ * Admin Command is sent using CSR by setting descriptor and buffer in specific
+ * registers.
+ *
+ * Return: the exit code of the operation.
+ * * - IXGBE_SUCCESS - success.
+ * * - IXGBE_ERR_ACI_DISABLED - CSR mechanism is not enabled.
+ * * - IXGBE_ERR_ACI_BUSY - CSR mechanism is busy.
+ * * - IXGBE_ERR_PARAM - buf_size is too big or
+ * invalid argument buf or buf_size.
+ * * - IXGBE_ERR_ACI_TIMEOUT - Admin Command X command timeout.
+ * * - IXGBE_ERR_ACI_ERROR - Admin Command X invalid state of HICR register or
+ * Admin Command failed because of bad opcode was returned or
+ * Admin Command failed with error Y.
+ */
+static s32
+ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc,
+                          void *buf, u16 buf_size)
+{
+       u32 hicr = 0, tmp_buf_size = 0, i = 0;
+       u32 *raw_desc = (u32 *)desc;
+       s32 status = IXGBE_SUCCESS;
+       bool valid_buf = false;
+       u32 *tmp_buf = NULL;
+       u16 opcode = 0;
+
+       do {
+               hw->aci.last_status = IXGBE_ACI_RC_OK;
+
+               /* It's necessary to check if mechanism is enabled */
+               hicr = IXGBE_READ_REG(hw, PF_HICR);
+               if (!(hicr & PF_HICR_EN)) {
+                       status = IXGBE_ERR_ACI_DISABLED;
+                       break;
+               }
+               if (hicr & PF_HICR_C) {
+                       hw->aci.last_status = IXGBE_ACI_RC_EBUSY;
+                       status = IXGBE_ERR_ACI_BUSY;
+                       break;
+               }
+               opcode = desc->opcode;
+
+               if (buf_size > IXGBE_ACI_MAX_BUFFER_SIZE) {
+                       status = IXGBE_ERR_PARAM;
+                       break;
+               }
+
+               if (buf)
+                       desc->flags |= IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_BUF);
+
+               /* Check if buf and buf_size are proper params */
+               if (desc->flags & IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_BUF)) {
+                       if ((buf && buf_size == 0) ||
+                           (buf == NULL && buf_size)) {
+                               status = IXGBE_ERR_PARAM;
+                               break;
+                       }
+                       if (buf && buf_size)
+                               valid_buf = true;
+               }
+
+               if (valid_buf == true) {
+                       if (buf_size % 4 == 0)
+                               tmp_buf_size = buf_size;
+                       else
+                               tmp_buf_size = (buf_size & (u16)(~0x03)) + 4;
+
+                       tmp_buf = (u32*)ixgbe_malloc(hw, tmp_buf_size);
+                       if (!tmp_buf)
+                               return IXGBE_ERR_OUT_OF_MEM;
+
+                       /* tmp_buf will be firstly filled with 0xFF and after
+                        * that the content of buf will be written into it.
+                        * This approach lets us use valid buf_size and
+                        * prevents us from reading past buf area
+                        * when buf_size mod 4 not equal to 0.
+                        */
+                       memset(tmp_buf, 0xFF, tmp_buf_size);
+                       memcpy(tmp_buf, buf, buf_size);
+
+                       if (tmp_buf_size > IXGBE_ACI_LG_BUF)
+                               desc->flags |=
+                               IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_LB);
+
+                       desc->datalen = IXGBE_CPU_TO_LE16(buf_size);
+
+                       if (desc->flags & IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_RD)) 
{
+                               for (i = 0; i < tmp_buf_size / 4; i++) {
+                                       IXGBE_WRITE_REG(hw, PF_HIBA(i),
+                                               IXGBE_LE32_TO_CPU(tmp_buf[i]));
+                               }
+                       }
+               }
+
+               /* Descriptor is written to specific registers */
+               for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++)
+                       IXGBE_WRITE_REG(hw, PF_HIDA(i),
+                                       IXGBE_LE32_TO_CPU(raw_desc[i]));
+
+               /* SW has to set PF_HICR.C bit and clear PF_HICR.SV and
+                * PF_HICR_EV
+                */
+               hicr = IXGBE_READ_REG(hw, PF_HICR);
+               hicr = (hicr | PF_HICR_C) & ~(PF_HICR_SV | PF_HICR_EV);
+               IXGBE_WRITE_REG(hw, PF_HICR, hicr);
+
+               /* Wait for sync Admin Command response */
+               for (i = 0; i < IXGBE_ACI_SYNC_RESPONSE_TIMEOUT; i += 1) {
+                       hicr = IXGBE_READ_REG(hw, PF_HICR);
+                       if ((hicr & PF_HICR_SV) || !(hicr & PF_HICR_C))
+                               break;
+
+                       msec_delay(1);
+               }
+
+               /* Wait for async Admin Command response */
+               if ((hicr & PF_HICR_SV) && (hicr & PF_HICR_C)) {
+                       for (i = 0; i < IXGBE_ACI_ASYNC_RESPONSE_TIMEOUT;
+                            i += 1) {
+                               hicr = IXGBE_READ_REG(hw, PF_HICR);
+                               if ((hicr & PF_HICR_EV) || !(hicr & PF_HICR_C))
+                                       break;
+
+                               msec_delay(1);
+                       }
+               }
+
+               /* Read sync Admin Command response */
+               if ((hicr & PF_HICR_SV)) {
+                       for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+                               raw_desc[i] = IXGBE_READ_REG(hw, PF_HIDA(i));
+                               raw_desc[i] = IXGBE_CPU_TO_LE32(raw_desc[i]);
+                       }
+               }
+
+               /* Read async Admin Command response */
+               if ((hicr & PF_HICR_EV) && !(hicr & PF_HICR_C)) {
+                       for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
+                               raw_desc[i] = IXGBE_READ_REG(hw, PF_HIDA_2(i));
+                               raw_desc[i] = IXGBE_CPU_TO_LE32(raw_desc[i]);
+                       }
*** 8201 LINES SKIPPED ***

Reply via email to