git: 13ee84c591f8 - main - ix(4): Add EEE support for E610 adapters
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 13 Mar 2026 11:53:44 UTC
The branch main has been updated by kgalazka:
URL: https://cgit.FreeBSD.org/src/commit/?id=13ee84c591f8df7553fc8e3dac7e92409046f4d2
commit 13ee84c591f8df7553fc8e3dac7e92409046f4d2
Author: Krzysztof Galazka <kgalazka@FreeBSD.org>
AuthorDate: 2026-03-13 11:48:12 +0000
Commit: Krzysztof Galazka <kgalazka@FreeBSD.org>
CommitDate: 2026-03-13 11:48:29 +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 <yogesh.bhosale@intel.com>
Signed-off-by: Krzysztof Galazka <krzysztof.galazka@intel.com>
Authored-by: Yogesh Bhosale <yogesh.bhosale@intel.com>
Approved by: kbowling (mentor)
Tested by: Mateusz Moga <mateusz.moga@intel.com>
MFC after: 2 weeks
Sponsored by: Intel Corporation
Differential Revision: https://reviews.freebsd.org/D55304
---
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 1d36fd11f368..88cbeb418ec6 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;
@@ -4589,6 +4593,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 */
@@ -5582,6 +5600,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);
@@ -5645,6 +5674,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 |
@@ -5700,6 +5731,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;