Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Mar 2026 11:53:44 +0000
From:      Krzysztof Galazka <kgalazka@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 13ee84c591f8 - main - ix(4): Add EEE support for E610 adapters
Message-ID:  <69b3fac8.1f291.2ef771c0@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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;


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69b3fac8.1f291.2ef771c0>