git: 8b2e75970c03 - main - ixl: Add led(4) identification support

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Wed, 12 Aug 2026 03:20:22 UTC
The branch main has been updated by kbowling:

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

commit 8b2e75970c0328e7397290417cc06e9d9c763d2a
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-12 00:54:21 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-12 03:16:08 +0000

    ixl: Add led(4) identification support
    
    Expose each physical port identification LED through /dev/led/ixl*.
    Use the existing GPIO LED helpers for most devices and the PHY
    provisioning interface for X710 10GBASE-T adapters.
    
    Preserve and restore the original GPIO or PHY indication mode,
    including before the interface is stopped.
    
    MFC after:      2 weeks
---
 share/man/man4/ixl.4       |  7 ++++-
 sys/dev/ixl/if_ixl.c       | 78 +++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/ixl/ixl_pf.h       |  5 +++
 sys/dev/ixl/ixl_pf_iflib.c |  2 ++
 4 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/ixl.4 b/share/man/man4/ixl.4
index 37d8c0cf5db8..b9c22e8b9b9c 100644
--- a/share/man/man4/ixl.4
+++ b/share/man/man4/ixl.4
@@ -29,7 +29,7 @@
 .\"
 .\" * Other names and brands may be claimed as the property of others.
 .\"
-.Dd August 9, 2026
+.Dd August 12, 2026
 .Dt IXL 4
 .Os
 .Sh NAME
@@ -88,6 +88,10 @@ and/or TSO6, and finally LRO can be set and unset.
 .Pp
 For more information on configuring this device, see
 .Xr ifconfig 8 .
+.Pp
+The identification LED for each port is controlled through its
+.Pa /dev/led/ixl*
+device node.
 .Ss Additional Utilities
 There are additional tools available from Intel to help configure and update
 the adapters covered by this driver.
@@ -301,6 +305,7 @@ email all the specific information related to the issue to
 .Xr arp 4 ,
 .Xr iavf 4 ,
 .Xr iflib 4 ,
+.Xr led 4 ,
 .Xr netintro 4 ,
 .Xr vlan 4 ,
 .Xr ifconfig 8 ,
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index 953882287386..886a4e52303c 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -122,6 +122,7 @@ static uint64_t	 ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt);
 static int	 ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req);
 static int	 ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
 static bool	 ixl_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
+static void	 ixl_if_led_func(if_ctx_t ctx, int onoff);
 #ifdef PCI_IOV
 static void	 ixl_if_vflr_handle(if_ctx_t ctx);
 #endif
@@ -193,13 +194,13 @@ static device_method_t ixl_if_methods[] = {
 	DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req),
 	DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl),
 	DEVMETHOD(ifdi_needs_restart, ixl_if_needs_restart),
+	DEVMETHOD(ifdi_led_func, ixl_if_led_func),
 #ifdef PCI_IOV
 	DEVMETHOD(ifdi_iov_init, ixl_if_iov_init),
 	DEVMETHOD(ifdi_iov_uninit, ixl_if_iov_uninit),
 	DEVMETHOD(ifdi_iov_vf_add, ixl_if_iov_vf_add),
 	DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle),
 #endif
-	// ifdi_led_func
 	// ifdi_debug
 	DEVMETHOD_END
 };
@@ -1063,6 +1064,7 @@ ixl_if_stop(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("ixl_if_stop: begin\n");
 
+	ixl_led_restore(pf);
 	if (IXL_PF_IN_RECOVERY_MODE(pf))
 		return;
 
@@ -1085,6 +1087,80 @@ ixl_if_stop(if_ctx_t ctx)
 		ixl_set_link(pf, false);
 }
 
+#define IXL_PHY_DEBUG_ALL					\
+	(I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW |			\
+	 I40E_AQ_PHY_DEBUG_DISABLE_ALL_LINK_FW)
+
+static bool
+ixl_phy_controls_leds(const struct i40e_hw *hw)
+{
+
+	/* These external 10GBASE-T PHYs own the identification LED. */
+	return (hw->device_id == I40E_DEV_ID_10G_BASE_T ||
+	    hw->device_id == I40E_DEV_ID_10G_BASE_T4);
+}
+
+static void
+ixl_if_led_func(if_ctx_t ctx, int onoff)
+{
+	struct ixl_pf *pf;
+	struct i40e_hw *hw;
+	enum i40e_status_code status;
+	u16 phy_status;
+
+	pf = iflib_get_softc(ctx);
+	hw = &pf->hw;
+	if (!onoff) {
+		ixl_led_restore(pf);
+		return;
+	}
+	if (pf->led_active)
+		return;
+
+	pf->led_phy_controlled = ixl_phy_controls_leds(hw);
+	if (!pf->led_phy_controlled) {
+		pf->led_status = i40e_led_get(hw);
+		pf->led_active = true;
+		i40e_led_set(hw, 0xf, false);
+		return;
+	}
+
+	if ((hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) == 0)
+		(void)i40e_aq_set_phy_debug(hw, IXL_PHY_DEBUG_ALL, NULL);
+	pf->led_phy_addr = I40E_PHY_LED_PROV_REG_1;
+	status = i40e_led_get_phy(hw, &pf->led_phy_addr, &phy_status);
+	if (status != I40E_SUCCESS) {
+		if ((hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) == 0)
+			(void)i40e_aq_set_phy_debug(hw, 0, NULL);
+		return;
+	}
+	pf->led_status = phy_status;
+	pf->led_active = true;
+	status = i40e_led_set_phy(hw, true, pf->led_phy_addr, 0);
+	if (status != I40E_SUCCESS)
+		ixl_led_restore(pf);
+}
+
+void
+ixl_led_restore(struct ixl_pf *pf)
+{
+	struct i40e_hw *hw;
+
+	if (!pf->led_active)
+		return;
+
+	hw = &pf->hw;
+	if (pf->led_phy_controlled) {
+		(void)i40e_led_set_phy(hw, false, pf->led_phy_addr,
+		    pf->led_status | I40E_PHY_LED_MODE_ORIG);
+		if ((hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) == 0)
+			(void)i40e_aq_set_phy_debug(hw, 0, NULL);
+	} else {
+		i40e_led_set(hw, pf->led_status, false);
+	}
+	pf->led_active = false;
+}
+
 static int
 ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
 {
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 74e1cad79731..7d751d3bd1dc 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -137,6 +137,10 @@ struct ixl_pf {
 #endif
 	u32			state;
 	u8			supported_speeds;
+	bool			led_active;
+	bool			led_phy_controlled;
+	u16			led_phy_addr;
+	u32			led_status;
 
 	struct ixl_pf_qmgr	qmgr;
 	struct ixl_pf_qtag	qtag;
@@ -388,6 +392,7 @@ void	ixl_shutdown_hmc(struct ixl_pf *);
 void	ixl_handle_empr_reset(struct ixl_pf *);
 int	ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up);
 int	ixl_rebuild_hw_structs_after_reset(struct ixl_pf *, bool is_up);
+void	ixl_led_restore(struct ixl_pf *pf);
 int	ixl_pf_reset(struct ixl_pf *);
 
 #ifdef PCI_IOV
diff --git a/sys/dev/ixl/ixl_pf_iflib.c b/sys/dev/ixl/ixl_pf_iflib.c
index bdacf0cfa06d..90fc85198523 100644
--- a/sys/dev/ixl/ixl_pf_iflib.c
+++ b/sys/dev/ixl/ixl_pf_iflib.c
@@ -944,6 +944,8 @@ ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up)
 	int error, first_error;
 
 	first_error = 0;
+	/* Restore identification before the reset tears down AdminQ access. */
+	ixl_led_restore(pf);
 #ifdef PCI_IOV
 	ixl_notify_vfs_reset(pf);
 	error = ixl_quiesce_vfs_for_reset(pf);