git: 98b5640786f8 - main - bnxt: Add led(4) identification support

Kevin Bowling <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src,gmane.os.freebsd.current.scm
Message-ID <[email protected]>
The branch main has been updated by kbowling:

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

commit 98b5640786f874949e441bee7c4ad5740cd6a649
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-12 01:29:31 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-13 15:32:07 +0000

    bnxt: Add led(4) identification support
    
    Query the firmware for the LEDs on each physical port and expose
    /dev/led/bnxt* only when alternate blinking is supported.  Configure
    every LED in the advertised group for identification and restore its
    default firmware state before a function reset.
    
    This follows the DPDK and Linux bnxt HWRM identification paths.
    
    Reviewed against: DPDK, Linux
    
    Reviewed by:    Sumit Saxena <[email protected]>
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
---
 share/man/man4/bnxt.4            |   7 ++-
 sys/dev/bnxt/bnxt_en/bnxt.h      |  15 ++++++
 sys/dev/bnxt/bnxt_en/bnxt_hwrm.c | 106 ++++++++++++++++++++++++++++++++++++++-
 sys/dev/bnxt/bnxt_en/bnxt_hwrm.h |   2 +
 sys/dev/bnxt/bnxt_en/if_bnxt.c   |  41 +++++++++++++++
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/bnxt.4 b/share/man/man4/bnxt.4
index 5e3ee27426d5..cedab9b83d00 100644
--- a/share/man/man4/bnxt.4
+++ b/share/man/man4/bnxt.4
@@ -23,7 +23,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd December 10, 2025
+.Dd August 11, 2026
 .Dt BNXT 4
 .Os
 .Sh NAME
@@ -52,6 +52,11 @@ BCM574XX, BCM575XX, and BCM576XX Ethernet controllers.
 .Pp
 For more information on configuring this device, see
 .Xr ifconfig 8 .
+.Pp
+On physical functions whose firmware reports identification LED support,
+the LEDs for each port are controlled through its
+.Pa /dev/led/bnxt*
+device node.
 .Sh HARDWARE
 The
 .Nm
diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index 7e58139f1ab6..d4167301ffff 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -468,6 +468,18 @@ struct bnxt_link_info {
 	uint8_t		active_lanes;
 };
 
+#define BNXT_MAX_LED	4
+
+/* Layout of one LED capability record returned by HWRM_PORT_LED_QCAPS. */
+struct bnxt_led_info {
+	uint8_t		led_id;
+	uint8_t		led_type;
+	uint8_t		led_group_id;
+	uint8_t		unused;
+	uint16_t	led_state_caps;
+	uint16_t	led_color_caps;
+};
+
 enum bnxt_phy_type {
 	BNXT_MEDIA_CR = 0,
 	BNXT_MEDIA_LR,
@@ -1099,6 +1111,9 @@ struct bnxt_softc {
 	struct bnxt_bar_info	hwrm_bar;
 	struct bnxt_bar_info	doorbell_bar;
 	struct bnxt_link_info	link_info;
+	struct bnxt_led_info	leds[BNXT_MAX_LED];
+	uint8_t			num_leds;
+	bool			led_active;
 #define BNXT_FLAG_VF				0x0001
 #define BNXT_FLAG_NPAR				0x0002
 #define BNXT_FLAG_WOL_CAP			0x0004
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
index 5964511f8276..a6742b6ca37c 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
@@ -74,6 +74,31 @@ static void	bnxt_hwrm_set_eee(struct bnxt_softc *softc,
 	BNXT_TX_STATS_PRI_ENTRY(counter, 6),		\
 	BNXT_TX_STATS_PRI_ENTRY(counter, 7)
 
+#define BNXT_LED_DFLT_ENA				\
+	(HWRM_PORT_LED_CFG_INPUT_ENABLES_LED0_ID |	\
+	 HWRM_PORT_LED_CFG_INPUT_ENABLES_LED0_STATE |	\
+	 HWRM_PORT_LED_CFG_INPUT_ENABLES_LED0_BLINK_ON |	\
+	 HWRM_PORT_LED_CFG_INPUT_ENABLES_LED0_BLINK_OFF |	\
+	 HWRM_PORT_LED_CFG_INPUT_ENABLES_LED0_GROUP_ID)
+#define BNXT_LED_DFLT_ENA_SHIFT	6
+#define BNXT_LED_DFLT_ENABLES(_i)			\
+	(BNXT_LED_DFLT_ENA << (BNXT_LED_DFLT_ENA_SHIFT * (_i)))
+#define BNXT_LED_ALT_BLINK_CAP \
+	HWRM_PORT_LED_QCAPS_OUTPUT_LED0_STATE_CAPS_BLINK_ALT_SUPPORTED
+
+struct bnxt_led_cfg {
+	uint8_t		led_id;
+	uint8_t		led_state;
+	uint8_t		led_color;
+	uint8_t		unused;
+	uint16_t	led_blink_on;
+	uint16_t	led_blink_off;
+	uint8_t		led_group_id;
+	uint8_t		reserved;
+};
+
+CTASSERT(sizeof(struct bnxt_led_info) == 8);
+CTASSERT(sizeof(struct bnxt_led_cfg) == 10);
 
 long bnxt_rx_bytes_pri_arr_base_off[] = {BNXT_RX_STATS_PRI_ENTRIES(rx_bytes)};
 long bnxt_rx_pkts_pri_arr_base_off[] = {BNXT_RX_STATS_PRI_ENTRIES(rx_packets)};
@@ -1331,6 +1356,86 @@ fail:
 	return rc;
 }
 
+int
+bnxt_hwrm_port_led_qcaps(struct bnxt_softc *softc)
+{
+	struct hwrm_port_led_qcaps_output *resp;
+	struct hwrm_port_led_qcaps_input req = {0};
+	struct bnxt_led_info *led;
+	uint16_t caps;
+	int i, rc;
+
+	softc->num_leds = 0;
+	if (BNXT_VF(softc) || softc->hwrm_spec_code < 0x10601)
+		return (0);
+
+	resp = (void *)softc->hwrm_cmd_resp.idi_vaddr;
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_LED_QCAPS);
+	req.port_id = htole16(softc->pf.port_id);
+
+	BNXT_HWRM_LOCK(softc);
+	rc = _hwrm_send_message(softc, &req, sizeof(req));
+	if (rc != 0)
+		goto out;
+
+	/* HWRM describes up to four LED records in both response and request. */
+	if (resp->num_leds == 0 || resp->num_leds > BNXT_MAX_LED)
+		goto out;
+	memcpy(softc->leds, &resp->led0_id,
+	    sizeof(softc->leds[0]) * resp->num_leds);
+	softc->num_leds = resp->num_leds;
+	for (i = 0; i < softc->num_leds; i++) {
+		led = &softc->leds[i];
+		caps = le16toh(led->led_state_caps);
+		if (led->led_group_id == 0 ||
+		    (caps & BNXT_LED_ALT_BLINK_CAP) == 0) {
+			softc->num_leds = 0;
+			break;
+		}
+	}
+out:
+	BNXT_HWRM_UNLOCK(softc);
+	return (rc);
+}
+
+int
+bnxt_hwrm_port_led_cfg(struct bnxt_softc *softc, bool led_on)
+{
+	struct hwrm_port_led_cfg_input req = {0};
+	struct bnxt_led_cfg *led_cfg;
+	uint32_t enables;
+	uint16_t duration;
+	uint8_t led_state;
+	int i;
+
+	if (BNXT_VF(softc) || softc->num_leds == 0)
+		return (EOPNOTSUPP);
+
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_LED_CFG);
+	req.port_id = htole16(softc->pf.port_id);
+	req.num_leds = softc->num_leds;
+	led_state = HWRM_PORT_LED_CFG_INPUT_LED0_STATE_DEFAULT;
+	duration = 0;
+	if (led_on) {
+		led_state = HWRM_PORT_LED_CFG_INPUT_LED0_STATE_BLINKALT;
+		duration = htole16(500);
+	}
+
+	enables = 0;
+	led_cfg = (struct bnxt_led_cfg *)(void *)&req.led0_id;
+	for (i = 0; i < softc->num_leds; i++, led_cfg++) {
+		enables |= BNXT_LED_DFLT_ENABLES(i);
+		led_cfg->led_id = softc->leds[i].led_id;
+		led_cfg->led_state = led_state;
+		led_cfg->led_blink_on = duration;
+		led_cfg->led_blink_off = duration;
+		led_cfg->led_group_id = softc->leds[i].led_group_id;
+	}
+	req.enables = htole32(enables);
+
+	return (hwrm_send_message(softc, &req, sizeof(req)));
+}
+
 int
 bnxt_hwrm_func_qcfg(struct bnxt_softc *softc)
 {
@@ -3446,4 +3551,3 @@ bnxt_hwrm_get_dump_len(struct bnxt_softc *softc, uint16_t dump_type,
 get_dump_len_exit:
 	return (rc);
 }
-
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
index b10981d9d53f..641a1e9ebe3a 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
@@ -69,6 +69,8 @@ int bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
 int bnxt_hwrm_stat_ctx_free(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr);
 int bnxt_hwrm_port_qstats(struct bnxt_softc *softc);
 int bnxt_hwrm_port_qstats_ext(struct bnxt_softc *softc);
+int bnxt_hwrm_port_led_qcaps(struct bnxt_softc *softc);
+int bnxt_hwrm_port_led_cfg(struct bnxt_softc *softc, bool led_on);
 int bnxt_hwrm_ring_grp_alloc(struct bnxt_softc *softc,
     struct bnxt_grp_info *grp);
 int bnxt_hwrm_ring_grp_free(struct bnxt_softc *softc, struct bnxt_grp_info *gr);
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 8ecb4770fe0e..ec88b30edcde 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -217,6 +217,9 @@ static int bnxt_detach(if_ctx_t ctx);
 static void bnxt_init(if_ctx_t ctx);
 static int bnxt_init_hw(if_ctx_t ctx);
 static void bnxt_stop(if_ctx_t ctx);
+static void bnxt_if_led_func(if_ctx_t ctx, int onoff);
+static bool bnxt_if_led_supported(if_ctx_t ctx);
+static void bnxt_led_restore(struct bnxt_softc *softc);
 static void bnxt_multi_set(if_ctx_t ctx);
 static int bnxt_mtu_set(if_ctx_t ctx, uint32_t mtu);
 static void bnxt_media_status(if_ctx_t ctx, struct ifmediareq * ifmr);
@@ -342,6 +345,8 @@ static device_method_t bnxt_iflib_methods[] = {
 
 	DEVMETHOD(ifdi_init, bnxt_init),
 	DEVMETHOD(ifdi_stop, bnxt_stop),
+	DEVMETHOD(ifdi_led_func, bnxt_if_led_func),
+	DEVMETHOD(ifdi_led_supported, bnxt_if_led_supported),
 	DEVMETHOD(ifdi_multi_set, bnxt_multi_set),
 	DEVMETHOD(ifdi_mtu_set, bnxt_mtu_set),
 	DEVMETHOD(ifdi_media_status, bnxt_media_status),
@@ -2244,6 +2249,7 @@ static int bnxt_open(struct bnxt_softc *bp)
 	rc = bnxt_hwrm_func_qcaps(bp);
 	if (rc)
 		return rc;
+	(void)bnxt_hwrm_port_led_qcaps(bp);
 
 	bnxt_hwrm_dbg_qcaps(bp);
 
@@ -2251,6 +2257,8 @@ static int bnxt_open(struct bnxt_softc *bp)
 	rc = bnxt_drv_rgtr(bp);
 	if (rc)
 		return rc;
+	/* Retry a restore which could not complete before firmware reset. */
+	bnxt_led_restore(bp);
 	if (bp->hwrm_spec_code >= 0x10803) {
 		rc = bnxt_alloc_ctx_mem(bp);
 		if (rc) {
@@ -2728,6 +2736,7 @@ bnxt_attach_pre(if_ctx_t ctx)
 	rc = bnxt_hwrm_func_qcaps(softc);
 	if (rc)
 		goto failed;
+	(void)bnxt_hwrm_port_led_qcaps(softc);
 
 	/* Inform PF to approve MAC as default VF MAC. */
 	if (BNXT_VF(softc)) {
@@ -3151,6 +3160,7 @@ fail:
 static void
 bnxt_func_reset(struct bnxt_softc *softc)
 {
+	bnxt_led_restore(softc);
 
 	if (!BNXT_CHIP_P5_PLUS(softc)) {
 		bnxt_hwrm_func_reset(softc);
@@ -3493,6 +3503,37 @@ bnxt_stop(if_ctx_t ctx)
 	return;
 }
 
+static void
+bnxt_if_led_func(if_ctx_t ctx, int onoff)
+{
+	struct bnxt_softc *softc = iflib_get_softc(ctx);
+	bool active;
+
+	active = onoff != 0;
+	if (active == softc->led_active)
+		return;
+	if (bnxt_hwrm_port_led_cfg(softc, active) == 0)
+		softc->led_active = active;
+}
+
+static void
+bnxt_led_restore(struct bnxt_softc *softc)
+{
+
+	if (!softc->led_active)
+		return;
+	if (bnxt_hwrm_port_led_cfg(softc, false) == 0)
+		softc->led_active = false;
+}
+
+static bool
+bnxt_if_led_supported(if_ctx_t ctx)
+{
+	struct bnxt_softc *softc = iflib_get_softc(ctx);
+
+	return (softc->num_leds != 0);
+}
+
 static u_int
 bnxt_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
 {
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.