git: f9ce33b0d8ef - main - ixgbe: Add 10GBase-BX BiDi SFP+ module support

Kevin Bowling <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7a0297.3c482.1922c135__38027.8674581618$1786380970$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kbowling:

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

commit f9ce33b0d8ef233063bd6c27bdba2580f97d9094
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-10 16:29:24 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-10 16:54:09 +0000

    ixgbe: Add 10GBase-BX BiDi SFP+ module support
    
    10G-BX optics use paired wavelengths to carry 10 Gb/s Ethernet over a
    single strand of single-mode fiber.  Their 10G compliance byte is
    empty, so identify them from the SFF-8472 nominal signaling rate and
    single-mode reach fields.
    
    When an EEPROM also advertises 1G BASE-BX10, give the complete 10G
    bitrate and reach signature precedence.  Otherwise retain FreeBSD's
    permissive 1G-BX identification rather than requiring a nominal
    1.3 GBd rate.
    
    MFC after:      2 weeks
    Relnotes:       yes
---
 sys/dev/ixgbe/if_ix.c       | 10 ++++++++
 sys/dev/ixgbe/ixgbe_82599.c |  7 ++++++
 sys/dev/ixgbe/ixgbe_phy.c   | 61 +++++++++++++++++++++++++++++++++++++++++----
 sys/dev/ixgbe/ixgbe_phy.h   |  3 +++
 sys/dev/ixgbe/ixgbe_type.h  |  3 +++
 sys/dev/ixgbe/ixgbe_x550.c  |  2 ++
 6 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index ba1f3121ae4f..9a59ce6b4fe8 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -1755,6 +1755,10 @@ ixgbe_add_media_types(if_ctx_t ctx)
 			ifmedia_add(sc->media, IFM_ETHER | IFM_1000_LX, 0,
 			    NULL);
 	}
+	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_BX) {
+		device_printf(dev, "Media supported: 10Gbase-BX\n");
+		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_BX, 0, NULL);
+	}
 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) {
 		ifmedia_add(sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
 		if (hw->phy.multispeed_fiber)
@@ -2896,6 +2900,9 @@ ixgbe_if_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
 			ifmr->ifm_active |= IFM_1000_LX | IFM_FDX;
 			break;
 		}
+	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_BX &&
+	    sc->link_speed == IXGBE_LINK_SPEED_10GB_FULL)
+		ifmr->ifm_active |= IFM_10G_BX | IFM_FDX;
 	if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM)
 		switch (sc->link_speed) {
 		case IXGBE_LINK_SPEED_10GB_FULL:
@@ -3028,6 +3035,9 @@ ixgbe_if_media_change(if_ctx_t ctx)
 		speed |= IXGBE_LINK_SPEED_1GB_FULL;
 		speed |= IXGBE_LINK_SPEED_10GB_FULL;
 		break;
+	case IFM_10G_BX:
+		speed |= IXGBE_LINK_SPEED_10GB_FULL;
+		break;
 	case IFM_10G_LRM:
 	case IFM_10G_LR:
 #ifndef IFM_ETH_XTYPE
diff --git a/sys/dev/ixgbe/ixgbe_82599.c b/sys/dev/ixgbe/ixgbe_82599.c
index d23c84743b33..c8f1fbb9983e 100644
--- a/sys/dev/ixgbe/ixgbe_82599.c
+++ b/sys/dev/ixgbe/ixgbe_82599.c
@@ -454,6 +454,13 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
 		goto out;
 	}
 
+	if (hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+	    hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1) {
+		*speed = IXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
+		goto out;
+	}
+
 	/*
 	 * Determine link capabilities based on the stored value of AUTOC,
 	 * which represents EEPROM defaults.  If AUTOC value has not
diff --git a/sys/dev/ixgbe/ixgbe_phy.c b/sys/dev/ixgbe/ixgbe_phy.c
index a614ffe50c0d..99bfebd3acf1 100644
--- a/sys/dev/ixgbe/ixgbe_phy.c
+++ b/sys/dev/ixgbe/ixgbe_phy.c
@@ -1299,8 +1299,12 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 	u8 oui_bytes[3] = {0, 0, 0};
 	u8 cable_tech = 0;
 	u8 cable_spec = 0;
+	u8 bitrate_nominal = 0;
+	u8 sm_length_100m = 0;
+	u8 sm_length_km = 0;
 	u8 retries;
 	u16 enforce_sfp = 0;
+	bool is_10g_bx = false;
 	static bool warned_once = false;
 
 	DEBUGFUNC("ixgbe_identify_sfp_module_generic");
@@ -1358,6 +1362,37 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		if (status != IXGBE_SUCCESS)
 			goto err_read_i2c_eeprom;
 
+		/*
+		 * SFF-8472 identifies 10G-BX by an empty 10G compliance
+		 * byte, a nominal 10.3 GBd rate, and at least 1 km of
+		 * single-mode fiber reach.  Resolve that strong signature
+		 * before falling back to the permissive 1G-BX check below.
+		 */
+		if (hw->mac.type != ixgbe_mac_82598EB &&
+		    comp_codes_10g == 0 &&
+		    (comp_codes_1g & (IXGBE_SFF_1GBASET_CAPABLE |
+		    IXGBE_SFF_1GBASESX_CAPABLE |
+		    IXGBE_SFF_1GBASELX_CAPABLE)) == 0 &&
+		    (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
+		    IXGBE_SFF_DA_ACTIVE_CABLE)) == 0) {
+			status = hw->phy.ops.read_i2c_eeprom(hw,
+			    IXGBE_SFF_BITRATE_NOMINAL, &bitrate_nominal);
+			if (status != IXGBE_SUCCESS)
+				goto err_read_i2c_eeprom;
+			if (bitrate_nominal == IXGBE_SFF_10G_BX_BITRATE) {
+				status = hw->phy.ops.read_i2c_eeprom(hw,
+				    IXGBE_SFF_SM_LENGTH_KM, &sm_length_km);
+				if (status != IXGBE_SUCCESS)
+					goto err_read_i2c_eeprom;
+				status = hw->phy.ops.read_i2c_eeprom(hw,
+				    IXGBE_SFF_SM_LENGTH_100M, &sm_length_100m);
+				if (status != IXGBE_SUCCESS)
+					goto err_read_i2c_eeprom;
+			}
+			is_10g_bx = bitrate_nominal == IXGBE_SFF_10G_BX_BITRATE &&
+			    (sm_length_km > 0 || sm_length_100m >= 10);
+		}
+
 		 /* ID Module
 		  * =========
 		  * 0   SFP_DA_CU
@@ -1437,6 +1472,13 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 				else
 					hw->phy.sfp_type =
 						ixgbe_sfp_type_1g_lx_core1;
+			} else if (is_10g_bx) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+					    ixgbe_sfp_type_10g_bx_core0;
+				else
+					hw->phy.sfp_type =
+					    ixgbe_sfp_type_10g_bx_core1;
 			} else if (comp_codes_1g & IXGBE_SFF_BASEBX10_CAPABLE) {
 				if (hw->bus.lan_id == 0)
 					hw->phy.sfp_type =
@@ -1536,7 +1578,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
-		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) {
 			hw->phy.type = ixgbe_phy_sfp_unsupported;
 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
 			goto out;
@@ -1557,7 +1601,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
 		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
-		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+		      hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)) {
 			/* Make sure we're a supported PHY type */
 			if (hw->phy.type == ixgbe_phy_sfp_intel) {
 				status = IXGBE_SUCCESS;
@@ -1612,6 +1658,9 @@ u64 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw)
 	hw->phy.ops.identify_sfp(hw);
 	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
 		return physical_layer;
+	if (hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core0 ||
+	    hw->phy.sfp_type == ixgbe_sfp_type_10g_bx_core1)
+		return IXGBE_PHYSICAL_LAYER_10GBASE_BX;
 
 	switch (hw->phy.type) {
 	case ixgbe_phy_sfp_passive_tyco:
@@ -1884,20 +1933,22 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
 
 	/*
-	 * Limiting active cables and 1G Phys must be initialized as
+	 * Limiting active cables, 10G-BX, and 1G PHYs must be initialized as
 	 * SR modules
 	 */
 	if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
 	    sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
 	    sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
 	    sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
-	    sfp_type == ixgbe_sfp_type_1g_bx_core0)
+	    sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
+	    sfp_type == ixgbe_sfp_type_10g_bx_core0)
 		sfp_type = ixgbe_sfp_type_srlr_core0;
 	else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
 		 sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
 		 sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
 		 sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
-		 sfp_type == ixgbe_sfp_type_1g_bx_core1)
+		 sfp_type == ixgbe_sfp_type_1g_bx_core1 ||
+		 sfp_type == ixgbe_sfp_type_10g_bx_core1)
 		sfp_type = ixgbe_sfp_type_srlr_core1;
 
 	/* Read offset to PHY init contents */
diff --git a/sys/dev/ixgbe/ixgbe_phy.h b/sys/dev/ixgbe/ixgbe_phy.h
index c1ba73851397..8768267a383a 100644
--- a/sys/dev/ixgbe/ixgbe_phy.h
+++ b/sys/dev/ixgbe/ixgbe_phy.h
@@ -50,6 +50,8 @@
 #define IXGBE_SFF_10GBE_COMP_CODES	0x3
 #define IXGBE_SFF_CABLE_TECHNOLOGY	0x8
 #define IXGBE_SFF_BITRATE_NOMINAL	0xC
+#define IXGBE_SFF_SM_LENGTH_KM		0xE
+#define IXGBE_SFF_SM_LENGTH_100M		0xF
 #define IXGBE_SFF_CABLE_SPEC_COMP	0x3C
 #define IXGBE_SFF_SFF_8472_SWAP		0x5C
 #define IXGBE_SFF_SFF_8472_COMP		0x5E
@@ -75,6 +77,7 @@
 #define IXGBE_SFF_10GBASESR_CAPABLE	0x10
 #define IXGBE_SFF_10GBASELR_CAPABLE	0x20
 #define IXGBE_SFF_BASEBX10_CAPABLE	0x40
+#define IXGBE_SFF_10G_BX_BITRATE	0x67
 #define IXGBE_SFF_SOFT_RS_SELECT_MASK	0x8
 #define IXGBE_SFF_SOFT_RS_SELECT_10G	0x8
 #define IXGBE_SFF_SOFT_RS_SELECT_1G	0x0
diff --git a/sys/dev/ixgbe/ixgbe_type.h b/sys/dev/ixgbe/ixgbe_type.h
index 648f790194db..4986673b65c4 100644
--- a/sys/dev/ixgbe/ixgbe_type.h
+++ b/sys/dev/ixgbe/ixgbe_type.h
@@ -3551,6 +3551,7 @@ typedef u64 ixgbe_physical_layer;
 #define IXGBE_PHYSICAL_LAYER_2500BASE_KX	0x10000
 #define IXGBE_PHYSICAL_LAYER_2500BASE_T		0x20000
 #define IXGBE_PHYSICAL_LAYER_5000BASE_T		0x40000
+#define IXGBE_PHYSICAL_LAYER_10GBASE_BX		0x80000
 
 /* Flow Control Data Sheet defined values
  * Calculation and defines taken from 802.1bb Annex O
@@ -3827,6 +3828,8 @@ enum ixgbe_sfp_type {
 	ixgbe_sfp_type_1g_lx_core1 = 14,
 	ixgbe_sfp_type_1g_bx_core0 = 15,
 	ixgbe_sfp_type_1g_bx_core1 = 16,
+	ixgbe_sfp_type_10g_bx_core0 = 17,
+	ixgbe_sfp_type_10g_bx_core1 = 18,
 	ixgbe_sfp_type_not_present = 0xFFFE,
 	ixgbe_sfp_type_unknown = 0xFFFF
 };
diff --git a/sys/dev/ixgbe/ixgbe_x550.c b/sys/dev/ixgbe/ixgbe_x550.c
index 2891bc258db8..4f708e03b00e 100644
--- a/sys/dev/ixgbe/ixgbe_x550.c
+++ b/sys/dev/ixgbe/ixgbe_x550.c
@@ -1508,6 +1508,8 @@ static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
 	case ixgbe_sfp_type_1g_lx_core1:
 	case ixgbe_sfp_type_1g_bx_core0:
 	case ixgbe_sfp_type_1g_bx_core1:
+	case ixgbe_sfp_type_10g_bx_core0:
+	case ixgbe_sfp_type_10g_bx_core1:
 		*linear = false;
 		break;
 	case ixgbe_sfp_type_unknown:
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.