git: fb7e249ce4fd - main - ixgbe: Add led(4) identification support

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

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

commit fb7e249ce4fd03fe53e4407efe661f9e94852bb6
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:06:41 +0000

    ixgbe: Add led(4) identification support
    
    Expose the physical port identification LED through /dev/led/ix*.
    Save and restore the NVM-selected LEDCTL value around each request.
    The X550 operations also clear their PHY manual override before the
    register is restored.
    
    Use the dedicated firmware port-identification command on E610.  Its
    interface selects between firmware blinking and the original mode
    rather than directly controlling LEDCTL.
    
    Restore the normal indication before a device stop or reset.
    
    MFC after:      2 weeks
---
 share/man/man4/ix.4   |  7 ++++++-
 sys/dev/ixgbe/if_ix.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ixgbe/ixgbe.h |  2 ++
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/share/man/man4/ix.4 b/share/man/man4/ix.4
index 7177f0f9c962..433ec164688e 100644
--- a/share/man/man4/ix.4
+++ b/share/man/man4/ix.4
@@ -29,7 +29,7 @@
 .\"
 .\" * Other names and brands may be claimed as the property of others.
 .\"
-.Dd August 10, 2026
+.Dd August 12, 2026
 .Dt IX 4
 .Os
 .Sh NAME
@@ -56,6 +56,10 @@ The
 driver provides support for Intel(R) 10Gb Ethernet PCIe adapters.
 The driver supports Jumbo Frames, MSIX, TSO, and RSS.
 .Pp
+The identification LED for each port is controlled through its
+.Pa /dev/led/ix*
+device node.
+.Pp
 For questions related to hardware requirements,
 refer to the documentation supplied with your Intel 10GbE adapter.
 All hardware requirements listed apply to use with
@@ -272,6 +276,7 @@ issue to
 .Xr altq 4 ,
 .Xr arp 4 ,
 .Xr iflib 4 ,
+.Xr led 4 ,
 .Xr netintro 4 ,
 .Xr ng_ether 4 ,
 .Xr polling 4 ,
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 8165d18998fd..8610bfad0d4c 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -200,6 +200,8 @@ static void ixgbe_if_vlan_register(if_ctx_t, u16);
 static void ixgbe_if_vlan_unregister(if_ctx_t, u16);
 static int  ixgbe_if_i2c_req(if_ctx_t, struct ifi2creq *);
 static bool ixgbe_if_needs_restart(if_ctx_t, enum iflib_restart_event);
+static void ixgbe_if_led_func(if_ctx_t, int);
+static void ixgbe_led_restore(struct ixgbe_softc *);
 int ixgbe_intr(void *);
 
 static int ixgbe_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
@@ -376,6 +378,7 @@ static device_method_t ixgbe_if_methods[] = {
 	DEVMETHOD(ifdi_i2c_req, ixgbe_if_i2c_req),
 	DEVMETHOD(ifdi_needs_restart, ixgbe_if_needs_restart),
 	DEVMETHOD(ifdi_priv_ioctl, ixgbe_if_priv_ioctl),
+	DEVMETHOD(ifdi_led_func, ixgbe_if_led_func),
 #ifdef PCI_IOV
 	DEVMETHOD(ifdi_iov_init, ixgbe_if_iov_init),
 	DEVMETHOD(ifdi_iov_uninit, ixgbe_if_iov_uninit),
@@ -4820,6 +4823,7 @@ ixgbe_if_stop(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("ixgbe_if_stop: begin\n");
 
+	ixgbe_led_restore(sc);
 	if (sc->feat_en & IXGBE_FEATURE_SRIOV) {
 		ixgbe_disable_mdd(hw);
 		ixgbe_quiesce_vfs(sc);
@@ -4845,6 +4849,56 @@ ixgbe_if_stop(if_ctx_t ctx)
 	return;
 } /* ixgbe_if_stop */
 
+/*
+ * Identify the physical port while retaining the NVM-selected LED mode.
+ * E610 exposes identification through firmware rather than LEDCTL.
+ */
+static void
+ixgbe_if_led_func(if_ctx_t ctx, int onoff)
+{
+	struct ixgbe_softc *sc;
+	struct ixgbe_hw *hw;
+
+	sc = iflib_get_softc(ctx);
+	hw = &sc->hw;
+	if (!onoff) {
+		ixgbe_led_restore(sc);
+		return;
+	}
+	if (sc->led_active)
+		return;
+
+	if (hw->mac.type == ixgbe_mac_E610) {
+		if (ixgbe_aci_set_port_id_led(hw, false) == IXGBE_SUCCESS)
+			sc->led_active = true;
+		return;
+	}
+
+	sc->ledctl_default = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+	if (ixgbe_led_on(hw, hw->mac.led_link_act) == IXGBE_SUCCESS)
+		sc->led_active = true;
+}
+
+static void
+ixgbe_led_restore(struct ixgbe_softc *sc)
+{
+	struct ixgbe_hw *hw;
+
+	if (!sc->led_active)
+		return;
+
+	hw = &sc->hw;
+	if (hw->mac.type == ixgbe_mac_E610) {
+		(void)ixgbe_aci_set_port_id_led(hw, true);
+	} else {
+		/* Clear any PHY manual override before restoring LEDCTL. */
+		(void)ixgbe_led_off(hw, hw->mac.led_link_act);
+		IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, sc->ledctl_default);
+		IXGBE_WRITE_FLUSH(hw);
+	}
+	sc->led_active = false;
+}
+
 /************************************************************************
  * ixgbe_link_speed_to_str - Convert link speed to string
  *
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index 3d06920352ec..85b8c3480edd 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -441,9 +441,11 @@ struct ixgbe_softc {
 	u32			link_speed;
 	bool			link_up;
 	bool			link_enabled;
+	bool			led_active;
 	u32			vector;
 	u16			dmac;
 	u32			phy_layer;
+	u32			ledctl_default;
 
 	/* Power management-related */
 	bool			wol_support;