git: f9ce33b0d8ef - main - ixgbe: Add 10GBase-BX BiDi SFP+ module support
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 10 Aug 2026 16:55:51 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=f9ce33b0d8ef233063bd6c27bdba2580f97d9094
commit f9ce33b0d8ef233063bd6c27bdba2580f97d9094
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-10 16:29:24 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
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: