The branch stable/14 has been updated by kgalazka:

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

commit 76597c000c7c43462792ac51afa5a8adc8f67d63
Author:     Krzysztof Galazka <[email protected]>
AuthorDate: 2026-03-13 11:48:12 +0000
Commit:     Krzysztof Galazka <[email protected]>
CommitDate: 2026-07-10 14:29:40 +0000

    ix(4): Add EEE support for E610 adapters
    
    The ix driver now supports Energy Efficient Ethernet (EEE) on Intel
    E610 devices. EEE allows the network interface to enter low-power
    states during periods of low link utilization, reducing power
    consumption while maintaining full performance when needed.
    
    E610 adapters provide EEE support through BASE-T PHY functionality.
    Due to this PHY-based implementation, EEE is supported only
    on 2.5Gb speeds and above.
    
    Signed-off-by: Yogesh Bhosale <[email protected]>
    Signed-off-by: Krzysztof Galazka <[email protected]>
    
    Authored-by: Yogesh Bhosale <[email protected]>
    
    Approved by:    kbowling (mentor)
    Tested by:      Mateusz Moga <[email protected]>
    Sponsored by:   Intel Corporation
    Differential Revision:  https://reviews.freebsd.org/D55304
    
    (cherry picked from commit 13ee84c591f8df7553fc8e3dac7e92409046f4d2)
---
 sys/dev/ixgbe/if_ix.c           | 34 ++++++++++++++++++++++++
 sys/dev/ixgbe/ixgbe_e610.c      | 48 ++++++++++++++++++++++++----------
 sys/dev/ixgbe/ixgbe_type_e610.h | 57 +++++++++++++++++++++++++++++++----------
 3 files changed, 112 insertions(+), 27 deletions(-)

diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 1f41eca6ffcd..adc3458cedd6 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -1066,6 +1066,10 @@ ixgbe_if_attach_pre(if_ctx_t ctx)
        /* Ensure SW/FW semaphore is free */
        ixgbe_init_swfw_semaphore(hw);
 
+       /* Enable EEE power saving */
+       if (sc->feat_en & IXGBE_FEATURE_EEE)
+               hw->mac.ops.setup_eee(hw, true);
+
        /* Set an initial default flow control value */
        hw->fc.requested_mode = ixgbe_flow_control;
 
@@ -4591,6 +4595,20 @@ ixgbe_if_update_admin_status(if_ctx_t ctx)
                                    "Link is up %s Full Duplex\n",
                                    ixgbe_link_speed_to_str(sc->link_speed));
                        sc->link_active = true;
+
+                       /* If link speed is <= 1Gbps and EEE is enabled,
+                        * log info.
+                        */
+                       if (sc->hw.mac.type == ixgbe_mac_E610 &&
+                           (sc->feat_en & IXGBE_FEATURE_EEE) &&
+                           sc->link_speed <= IXGBE_LINK_SPEED_1GB_FULL) {
+                               device_printf(sc->dev,
+                                   "Energy Efficient Ethernet (EEE) feature "
+                                   "is not supported on link speeds equal to "
+                                   "or below 1Gbps. EEE is supported on "
+                                   "speeds above 1Gbps.\n");
+                       }
+
                        /* Update any Flow Control changes */
                        ixgbe_fc_enable(&sc->hw);
                        /* Update DMA coalescing config */
@@ -5584,6 +5602,17 @@ ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS)
        if ((new_eee < 0) || (new_eee > 1))
                return (EINVAL);
 
+       /* If link speed is <= 1Gbps and EEE is being enabled, log info */
+       if (sc->hw.mac.type == ixgbe_mac_E610 &&
+           new_eee &&
+           sc->link_speed <= IXGBE_LINK_SPEED_1GB_FULL) {
+               device_printf(dev,
+                   "Energy Efficient Ethernet (EEE) feature is not "
+                   "supported on link speeds equal to or below 1Gbps. "
+                   "EEE is supported on speeds above 1Gbps.\n");
+               return (EINVAL);
+       }
+
        retval = ixgbe_setup_eee(&sc->hw, new_eee);
        if (retval) {
                device_printf(dev, "Error in EEE setup: 0x%08X\n", retval);
@@ -5647,6 +5676,8 @@ ixgbe_sysctl_tso_tcp_flags_mask(SYSCTL_HANDLER_ARGS)
 static void
 ixgbe_init_device_features(struct ixgbe_softc *sc)
 {
+       s32 error;
+
        sc->feat_cap = IXGBE_FEATURE_NETMAP |
            IXGBE_FEATURE_RSS |
            IXGBE_FEATURE_MSI |
@@ -5702,6 +5733,9 @@ ixgbe_init_device_features(struct ixgbe_softc *sc)
        case ixgbe_mac_E610:
                sc->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
                sc->feat_cap |= IXGBE_FEATURE_DBG_DUMP;
+               error = ixgbe_get_caps(&sc->hw);
+               if (error == 0 && sc->hw.func_caps.common_cap.eee_support != 0)
+                       sc->feat_cap |= IXGBE_FEATURE_EEE;
                break;
        default:
                break;
diff --git a/sys/dev/ixgbe/ixgbe_e610.c b/sys/dev/ixgbe/ixgbe_e610.c
index 18c4612446e0..b76d96814933 100644
--- a/sys/dev/ixgbe/ixgbe_e610.c
+++ b/sys/dev/ixgbe/ixgbe_e610.c
@@ -776,6 +776,10 @@ ixgbe_parse_common_caps(struct ixgbe_hw *hw, struct 
ixgbe_hw_common_caps *caps,
                DEBUGOUT2("%s: next_cluster_id_support = %d\n",
                          prefix, caps->next_cluster_id_support);
                break;
+       case IXGBE_ACI_CAPS_EEE:
+               caps->eee_support = (u8)number;
+               DEBUGOUT2("%s: eee_support = %x\n", prefix, caps->eee_support);
+               break;
        default:
                /* Not one of the recognized common capabilities */
                found = false;
@@ -1332,6 +1336,7 @@ void ixgbe_copy_phy_caps_to_cfg(struct 
ixgbe_aci_cmd_get_phy_caps_data *caps,
        cfg->link_fec_opt = caps->link_fec_options;
        cfg->module_compliance_enforcement =
                caps->module_compliance_enforcement;
+       cfg->eee_entry_delay = caps->eee_entry_delay;
 }
 
 /**
@@ -1351,10 +1356,12 @@ s32 ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
                          struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
 {
        struct ixgbe_aci_desc desc;
+       bool use_1p40_buff;
        s32 status;
 
        if (!cfg)
                return IXGBE_ERR_PARAM;
+       use_1p40_buff = hw->func_caps.common_cap.eee_support != 0;
 
        /* Ensure that only valid bits of cfg->caps can be turned on. */
        if (cfg->caps & ~IXGBE_ACI_PHY_ENA_VALID_MASK) {
@@ -1364,8 +1371,18 @@ s32 ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
        ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
        desc.flags |= IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_RD);
 
-       status = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
+       if (use_1p40_buff) {
+               status = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
+       } else {
+               struct ixgbe_aci_cmd_set_phy_cfg_data_pre_1_40 cfg_obsolete;
+
+               memcpy(&cfg_obsolete, cfg, sizeof(cfg_obsolete));
+
+               status = ixgbe_aci_send_cmd(hw, &desc, &cfg_obsolete,
+                                           sizeof(cfg_obsolete));
+       }
 
+       /* even if the old buffer is used no need to worry about conversion */
        if (!status)
                hw->phy.curr_user_phy_cfg = *cfg;
 
@@ -1599,6 +1616,7 @@ s32 ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool 
ena_lse,
        li->topo_media_conflict = link_data.topo_media_conflict;
        li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
                                      IXGBE_ACI_CFG_PACING_TYPE_M);
+       li->eee_status = link_data.eee_status;
 
        /* update fc info */
        tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
@@ -3883,9 +3901,14 @@ s32 ixgbe_init_ops_E610(struct ixgbe_hw *hw)
        /* PHY */
        phy->ops.init = ixgbe_init_phy_ops_E610;
        phy->ops.identify = ixgbe_identify_phy_E610;
-       phy->eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
-                                   IXGBE_LINK_SPEED_100_FULL |
-                                   IXGBE_LINK_SPEED_1GB_FULL;
+
+       if (hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
+               phy->eee_speeds_supported = IXGBE_LINK_SPEED_2_5GB_FULL;
+       else
+               phy->eee_speeds_supported = IXGBE_LINK_SPEED_2_5GB_FULL |
+                                           IXGBE_LINK_SPEED_5GB_FULL |
+                                           IXGBE_LINK_SPEED_10GB_FULL;
+
        phy->eee_speeds_advertised = phy->eee_speeds_supported;
 
        /* Additional ops overrides for e610 to go here */
@@ -4513,19 +4536,18 @@ s32 ixgbe_setup_eee_E610(struct ixgbe_hw *hw, bool 
enable_eee)
        phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
        phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
 
+       /* setup only speeds which are defined for [0x0601/0x0600].eee_cap */
        if (enable_eee) {
-               if (phy_caps.phy_type_low & IXGBE_PHY_TYPE_LOW_100BASE_TX)
+               if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_100_FULL)
                        eee_cap |= IXGBE_ACI_PHY_EEE_EN_100BASE_TX;
-               if (phy_caps.phy_type_low & IXGBE_PHY_TYPE_LOW_1000BASE_T)
+               if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_1GB_FULL)
                        eee_cap |= IXGBE_ACI_PHY_EEE_EN_1000BASE_T;
-               if (phy_caps.phy_type_low & IXGBE_PHY_TYPE_LOW_1000BASE_KX)
-                       eee_cap |= IXGBE_ACI_PHY_EEE_EN_1000BASE_KX;
-               if (phy_caps.phy_type_low & IXGBE_PHY_TYPE_LOW_10GBASE_T)
+               if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
+                       eee_cap |= IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T;
+               if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_5GB_FULL)
+                       eee_cap |= IXGBE_ACI_PHY_EEE_EN_5GBASE_T;
+               if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_10GB_FULL)
                        eee_cap |= IXGBE_ACI_PHY_EEE_EN_10GBASE_T;
-               if (phy_caps.phy_type_low & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1)
-                       eee_cap |= IXGBE_ACI_PHY_EEE_EN_10GBASE_KR;
-               if (phy_caps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T)
-                       eee_cap |= IXGBE_ACI_PHY_EEE_EN_10BASE_T;
        }
 
        /* Set EEE capability for particular PHY types */
diff --git a/sys/dev/ixgbe/ixgbe_type_e610.h b/sys/dev/ixgbe/ixgbe_type_e610.h
index e300030c3ba4..da46e503f660 100644
--- a/sys/dev/ixgbe/ixgbe_type_e610.h
+++ b/sys/dev/ixgbe/ixgbe_type_e610.h
@@ -721,6 +721,7 @@ struct ixgbe_aci_cmd_list_caps_elem {
 #define IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3               0x0084
 #define IXGBE_ACI_CAPS_OROM_RECOVERY_UPDATE            0x0090
 #define IXGBE_ACI_CAPS_NEXT_CLUSTER_ID                 0x0096
+#define IXGBE_ACI_CAPS_EEE                             0x009B
        u8 major_ver;
        u8 minor_ver;
        /* Number of resources described by this capability */
@@ -836,10 +837,8 @@ struct ixgbe_aci_cmd_get_phy_caps_data {
 #define IXGBE_ACI_PHY_EEE_EN_100BASE_TX                        BIT(0)
 #define IXGBE_ACI_PHY_EEE_EN_1000BASE_T                        BIT(1)
 #define IXGBE_ACI_PHY_EEE_EN_10GBASE_T                 BIT(2)
-#define IXGBE_ACI_PHY_EEE_EN_1000BASE_KX               BIT(3)
-#define IXGBE_ACI_PHY_EEE_EN_10GBASE_KR                        BIT(4)
-#define IXGBE_ACI_PHY_EEE_EN_25GBASE_KR                        BIT(5)
-#define IXGBE_ACI_PHY_EEE_EN_10BASE_T                  BIT(11)
+#define IXGBE_ACI_PHY_EEE_EN_5GBASE_T                  BIT(11)
+#define IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T                        BIT(12)
        __le16 eeer_value;
        u8 phy_id_oui[4]; /* PHY/Module ID connected on the port */
        u8 phy_fw_ver[8];
@@ -869,7 +868,9 @@ struct ixgbe_aci_cmd_get_phy_caps_data {
 #define IXGBE_ACI_MOD_TYPE_BYTE2_SFP_PLUS              0xA0
 #define IXGBE_ACI_MOD_TYPE_BYTE2_QSFP_PLUS             0x86
        u8 qualified_module_count;
-       u8 rsvd2[7];    /* Bytes 47:41 reserved */
+       u8 rsvd2;
+       __le16 eee_entry_delay;
+       u8 rsvd3[4];
 #define IXGBE_ACI_QUAL_MOD_COUNT_MAX                   16
        struct {
                u8 v_oui[3];
@@ -893,11 +894,38 @@ struct ixgbe_aci_cmd_set_phy_cfg {
 
 IXGBE_CHECK_PARAM_LEN(ixgbe_aci_cmd_set_phy_cfg);
 
+/* Set PHY config obsolete command data structure (<FW 1.40) */
+struct ixgbe_aci_cmd_set_phy_cfg_data_pre_1_40 {
+       __le64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
+       __le64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
+       u8 caps;
+       u8 low_power_ctrl_an;
+       __le16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
+       __le16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
+       u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
+       u8 module_compliance_enforcement;
+};
+
+IXGBE_CHECK_STRUCT_LEN(24, ixgbe_aci_cmd_set_phy_cfg_data_pre_1_40);
+
+#pragma pack(1)
 /* Set PHY config command data structure */
 struct ixgbe_aci_cmd_set_phy_cfg_data {
        __le64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
        __le64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
        u8 caps;
+       u8 low_power_ctrl_an;
+       __le16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
+       __le16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
+       u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
+       u8 module_compliance_enforcement;
+       __le16  eee_entry_delay;
+};
+
+IXGBE_CHECK_STRUCT_LEN(26, ixgbe_aci_cmd_set_phy_cfg_data);
+#pragma pack()
+
+/* Set PHY config capabilities (@caps) defines */
 #define IXGBE_ACI_PHY_ENA_VALID_MASK           MAKEMASK(0xef, 0)
 #define IXGBE_ACI_PHY_ENA_TX_PAUSE_ABILITY     BIT(0)
 #define IXGBE_ACI_PHY_ENA_RX_PAUSE_ABILITY     BIT(1)
@@ -906,14 +934,7 @@ struct ixgbe_aci_cmd_set_phy_cfg_data {
 #define IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT       BIT(5)
 #define IXGBE_ACI_PHY_ENA_LESM                 BIT(6)
 #define IXGBE_ACI_PHY_ENA_AUTO_FEC             BIT(7)
-       u8 low_power_ctrl_an;
-       __le16 eee_cap; /* Value from ixgbe_aci_get_phy_caps */
-       __le16 eeer_value; /* Use defines from ixgbe_aci_get_phy_caps */
-       u8 link_fec_opt; /* Use defines from ixgbe_aci_get_phy_caps */
-       u8 module_compliance_enforcement;
-};
 
-IXGBE_CHECK_STRUCT_LEN(24, ixgbe_aci_cmd_set_phy_cfg_data);
 
 /* Restart AN command data structure (direct 0x0605)
  * Also used for response, with only the lport_num field present.
@@ -1035,8 +1056,9 @@ struct ixgbe_aci_cmd_get_link_status_data {
 #define IXGBE_ACI_LINK_SPEED_200GB             BIT(11)
 #define IXGBE_ACI_LINK_SPEED_UNKNOWN           BIT(15)
        __le16 reserved3; /* Aligns next field to 8-byte boundary */
-       u8 ext_fec_status;
-#define IXGBE_ACI_LINK_RS_272_FEC_EN   BIT(0) /* RS 272 FEC enabled */
+       u8 eee_status;
+#define IXGBE_ACI_LINK_EEE_ENABLED             BIT(2)
+#define IXGBE_ACI_LINK_EEE_ACTIVE              BIT(3)
        u8 reserved4;
        __le64 phy_type_low; /* Use values from IXGBE_PHY_TYPE_LOW_* */
        __le64 phy_type_high; /* Use values from IXGBE_PHY_TYPE_HIGH_* */
@@ -2034,6 +2056,7 @@ struct ixgbe_link_status {
         * ixgbe_aci_get_phy_caps structure
         */
        u8 module_type[IXGBE_ACI_MODULE_TYPE_TOTAL_BYTE];
+       u8 eee_status;
 };
 
 /* Common HW capabilities for SW use */
@@ -2112,6 +2135,12 @@ struct ixgbe_hw_common_caps {
        u8 apm_wol_support;
        u8 acpi_prog_mthd;
        u8 proxy_support;
+       u8 eee_support;
+#define IXGBE_EEE_SUPPORT_100BASE_TX   BIT(0)
+#define IXGBE_EEE_SUPPORT_1000BASE_T   BIT(1)
+#define IXGBE_EEE_SUPPORT_10GBASE_T    BIT(2)
+#define IXGBE_EEE_SUPPORT_5GBASE_T     BIT(3)
+#define IXGBE_EEE_SUPPORT_2_5GBASE_T   BIT(4)
        bool sec_rev_disabled;
        bool update_disabled;
        bool nvm_unified_update;

Reply via email to