git: e009e1fd8083 - main - if_bnxt: honor firmware min wait before VER_GET on reset

From: Sumit Saxena <ssaxena_at_FreeBSD.org>
Date: Fri, 09 Oct 2026 10:12:43 UTC
The branch main has been updated by ssaxena:

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

commit e009e1fd80839a4a570a73dae9011a04ed4579ca
Author:     Sumit Saxena <sumit.saxena@broadcom.com>
AuthorDate: 2026-07-31 15:46:25 +0000
Commit:     Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-10-09 08:24:43 +0000

    if_bnxt: honor firmware min wait before VER_GET on reset
    
    The firmware advertises a minimum wait time it needs before it is
    ready. The driver was not honoring it and sent VER_GET too early
    during firmware error-recovery, which could return an incomplete
    VER_GET buffer. Enforce that minimum wait, measured from when the
    RESET_NOTIFY async event arrived, before sending VER_GET.
    
    Reviewed by:    gallatin
    MFC after:      2 weeks
    Sponsored by:   Broadcom Inc.
    Differential Revision:  https://reviews.freebsd.org/D58608
---
 sys/dev/bnxt/bnxt_en/bnxt.h    |  2 ++
 sys/dev/bnxt/bnxt_en/if_bnxt.c | 19 +++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index e50c4157ac0b..09092cf7d59e 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -1509,6 +1509,8 @@ struct bnxt_softc {
 	u16			fw_reset_max_dsecs;
 #define BNXT_DFLT_FW_RST_MAX_DSECS	60
 	unsigned long		fw_reset_timestamp;
+	unsigned long		fw_reset_notify_timestamp;
+	u16			fw_reset_req_min_dsecs;
 
 	struct bnxt_fw_health	*fw_health;
 	char			board_partno[64];
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 2ea1fc97fd92..f6aeab9095d6 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -1932,6 +1932,21 @@ static u32 bnxt_fw_health_readl(struct bnxt_softc *bp, int reg_idx)
 	return val;
 }
 
+/*
+ * Sleep until at least min_ms milliseconds have passed since start_jiffies.
+ */
+static void bnxt_sleep_until_min_elapsed(unsigned long start_jiffies,
+    unsigned int min_ms)
+{
+	unsigned long elapsed_time;
+	unsigned int elapsed_time_ms;
+
+	elapsed_time = jiffies - start_jiffies;
+	elapsed_time_ms = (unsigned int)(elapsed_time * 1000 / HZ);
+	if (elapsed_time_ms < min_ms)
+		msleep(min_ms - elapsed_time_ms);
+}
+
 static void bnxt_fw_reset_close(struct bnxt_softc *bp)
 {
 	int i;
@@ -2443,6 +2458,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)
 		fallthrough;
 	case BNXT_FW_RESET_STATE_POLL_FW:
 		bp->hwrm_cmd_timeo = SHORT_HWRM_CMD_TIMEOUT;
+		bnxt_sleep_until_min_elapsed(bp->fw_reset_notify_timestamp,
+		    bp->fw_reset_req_min_dsecs * 100);
 		rc = bnxt_hwrm_poll(bp);
 		if (rc) {
 			if (bnxt_fw_reset_timeout(bp)) {
@@ -5667,9 +5684,11 @@ bnxt_handle_async_event(struct bnxt_softc *softc, struct cmpl_base *cmpl)
 			goto async_event_process_exit;
 
 		softc->fw_reset_timestamp = jiffies;
+		softc->fw_reset_notify_timestamp = jiffies;
 		softc->fw_reset_min_dsecs = ae->timestamp_lo;
 		if (!softc->fw_reset_min_dsecs)
 			softc->fw_reset_min_dsecs = BNXT_DFLT_FW_RST_MIN_DSECS;
+		softc->fw_reset_req_min_dsecs = softc->fw_reset_min_dsecs;
 		softc->fw_reset_max_dsecs = le16toh(ae->timestamp_hi);
 		if (!softc->fw_reset_max_dsecs)
 			softc->fw_reset_max_dsecs = BNXT_DFLT_FW_RST_MAX_DSECS;