git: 19f75b38199b - main - igc: Add led(4) identification support

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

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

commit 19f75b38199b9d30e85fab83e61ff36b0b9ed015
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-12 00:22:35 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-12 02:48:40 +0000

    igc: Add led(4) identification support
    
    I225 and I226 expose three programmable LED outputs.  Use LED1 for
    adapter identification, following the convention in DPDK.  Preserve the
    OEM configuration across identification requests.
    
    Restore the OEM configuration before a device reset so an active led(4)
    pattern cannot leave the output overridden across stop or detach.
    
    The LED mode values follow the Intel I225 Software User Manual.
    
    MFC after:      2 weeks
---
 share/man/man4/igc.4      | 10 +++++++++-
 sys/dev/igc/if_igc.c      | 45 +++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/igc/if_igc.h      |  4 ++--
 sys/dev/igc/igc_defines.h |  7 +++++--
 4 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/share/man/man4/igc.4 b/share/man/man4/igc.4
index 521a36531208..1fe87421738d 100644
--- a/share/man/man4/igc.4
+++ b/share/man/man4/igc.4
@@ -3,7 +3,7 @@
 .\" Copyright 2021 Rubicon Communications, LLC (Netgate)
 .\" SPDX-License-Identifier: BSD-3-Clause
 .\"
-.Dd August 3, 2026
+.Dd August 11, 2026
 .Dt IGC 4
 .Os
 .Sh NAME
@@ -43,6 +43,13 @@ This driver version supports VLAN hardware insertion / extraction,
 VLAN checksum offload, and VLAN hardware filtering.
 For information on enabling VLANs, see
 .Xr ifconfig 8 .
+.Pp
+The identification LED of an adapter supported by the
+.Nm
+driver can be controlled via the
+.Xr led 4
+interface at
+.Pa /dev/led/igc* .
 The
 .Nm
 driver supports the following media types:
@@ -154,6 +161,7 @@ address.
 .Xr altq 4 ,
 .Xr arp 4 ,
 .Xr iflib 4 ,
+.Xr led 4 ,
 .Xr netintro 4 ,
 .Xr ng_ether 4 ,
 .Xr vlan 4 ,
diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
index 8753209e8ea6..574cab87c305 100644
--- a/sys/dev/igc/if_igc.c
+++ b/sys/dev/igc/if_igc.c
@@ -139,6 +139,8 @@ static bool	igc_if_vlan_filter_used(if_ctx_t);
 static void	igc_if_vlan_filter_enable(struct igc_softc *);
 static void	igc_if_vlan_filter_disable(struct igc_softc *);
 static void	igc_setup_vlan_hw_support(if_ctx_t);
+static void	igc_if_led_func(if_ctx_t, int);
+static void	igc_led_restore(struct igc_softc *);
 static void	igc_fw_version(struct igc_softc *);
 static void	igc_sbuf_fw_version(struct igc_fw_version *, struct sbuf *);
 static void	igc_print_fw_version(struct igc_softc *);
@@ -231,6 +233,7 @@ static device_method_t igc_if_methods[] = {
 	DEVMETHOD(ifdi_tx_queue_intr_enable, igc_if_tx_queue_intr_enable),
 	DEVMETHOD(ifdi_debug, igc_if_debug),
 	DEVMETHOD(ifdi_needs_restart, igc_if_needs_restart),
+	DEVMETHOD(ifdi_led_func, igc_if_led_func),
 	DEVMETHOD_END
 };
 
@@ -1497,10 +1500,51 @@ igc_if_stop(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("igc_if_stop: begin");
 
+	igc_led_restore(sc);
 	igc_reset_hw(&sc->hw);
 	IGC_WRITE_REG(&sc->hw, IGC_WUC, 0);
 }
 
+/*
+ * I225/I226 have three configurable LED outputs.  DPDK uses LED1 for
+ * adapter identification; retain that convention and preserve the OEM's
+ * configuration for normal link and activity indication.
+ */
+static void
+igc_if_led_func(if_ctx_t ctx, int onoff)
+{
+	struct igc_softc *sc;
+	struct igc_hw *hw;
+	u32 ledctl;
+
+	sc = iflib_get_softc(ctx);
+	hw = &sc->hw;
+	if (onoff) {
+		if (!sc->led_active) {
+			sc->ledctl_default = IGC_READ_REG(hw, IGC_LEDCTL);
+			sc->led_active = true;
+		}
+		ledctl = sc->ledctl_default;
+		ledctl &= ~(IGC_LEDCTL_LED1_MODE_MASK |
+		    IGC_LEDCTL_LED1_BLINK);
+		ledctl |= IGC_LEDCTL_MODE_LED_ON <<
+		    IGC_LEDCTL_LED1_MODE_SHIFT;
+		IGC_WRITE_REG(hw, IGC_LEDCTL, ledctl);
+	} else {
+		igc_led_restore(sc);
+	}
+}
+
+static void
+igc_led_restore(struct igc_softc *sc)
+{
+
+	if (!sc->led_active)
+		return;
+	IGC_WRITE_REG(&sc->hw, IGC_LEDCTL, sc->ledctl_default);
+	sc->led_active = false;
+}
+
 /*********************************************************************
  *
  *  Determine hardware revision.
@@ -1888,6 +1932,7 @@ igc_reset(if_ctx_t ctx)
 	u32 pba;
 
 	INIT_DEBUGOUT("igc_reset: begin");
+	igc_led_restore(sc);
 	/* Let the firmware know the OS is in control */
 	igc_get_hw_control(sc);
 
diff --git a/sys/dev/igc/if_igc.h b/sys/dev/igc/if_igc.h
index 57b3fdcb0f13..c98f17a97ca3 100644
--- a/sys/dev/igc/if_igc.h
+++ b/sys/dev/igc/if_igc.h
@@ -81,7 +81,6 @@
 #include <netinet/udp.h>
 
 #include <machine/in_cksum.h>
-#include <dev/led/led.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 
@@ -350,7 +349,8 @@ struct igc_softc {
 	/* FreeBSD operating-system-specific structures. */
 	struct igc_osdep osdep;
 	device_t	dev;
-	struct cdev	*led_dev;
+	u32		ledctl_default;
+	bool		led_active;
 
         struct igc_tx_queue *tx_queues;
         struct igc_rx_queue *rx_queues;
diff --git a/sys/dev/igc/igc_defines.h b/sys/dev/igc/igc_defines.h
index 9fc1c72022c3..885f0799f6a6 100644
--- a/sys/dev/igc/igc_defines.h
+++ b/sys/dev/igc/igc_defines.h
@@ -297,9 +297,12 @@
 #define IGC_LEDCTL_LED0_MODE_SHIFT	0
 #define IGC_LEDCTL_LED0_IVRT		0x00000040
 #define IGC_LEDCTL_LED0_BLINK		0x00000080
+#define IGC_LEDCTL_LED1_MODE_MASK	0x00000F00
+#define IGC_LEDCTL_LED1_MODE_SHIFT	8
+#define IGC_LEDCTL_LED1_BLINK		0x00008000
 
-#define IGC_LEDCTL_MODE_LED_ON	0xE
-#define IGC_LEDCTL_MODE_LED_OFF	0xF
+#define IGC_LEDCTL_MODE_LED_ON	0x0
+#define IGC_LEDCTL_MODE_LED_OFF	0x1
 
 /* Transmit Descriptor bit definitions */
 #define IGC_TXD_DTYP_D	0x00100000 /* Data Descriptor */