git: 4f20e02ed058 - main - if_bnxt: dcb: serialize HWRM sends and avoid freeing DMA bufs on timeout

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

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

commit 4f20e02ed0582bd8a3e2b59853690c1d46e08fa8
Author:     Sumit Saxena <sumit.saxena@broadcom.com>
AuthorDate: 2026-09-29 12:15:06 +0000
Commit:     Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-10-09 08:24:46 +0000

    if_bnxt: dcb: serialize HWRM sends and avoid freeing DMA bufs on timeout
    
    Every _hwrm_send_message() call in bnxt_dcb.c ran without BNXT_HWRM_LOCK,
    unlike the rest of the driver, letting concurrent HWRM commands race on
    the shared MMIO doorbell and response buffer. Route single-shot sends
    through the already-locked hwrm_send_message() wrapper, and wrap the
    remaining send+response-read sequences in explicit BNXT_HWRM_LOCK/UNLOCK.
    
    Also stop freeing the transient DMA buffers used for structured-data
    get/set on ETIMEDOUT: a host-side timeout doesn't guarantee firmware
    actually gave up, so a late completion could still DMA into memory
    that's since been freed and reused. Leak the buffer instead in that case.
    
    Reviewed by:    gallatin
    MFC after:      2 weeks
    Sponsored by:   Broadcom Inc.
    Differential Revision:  https://reviews.freebsd.org/D60179
---
 sys/dev/bnxt/bnxt_en/bnxt_dcb.c | 52 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)

diff --git a/sys/dev/bnxt/bnxt_en/bnxt_dcb.c b/sys/dev/bnxt/bnxt_en/bnxt_dcb.c
index d169be6e5c7b..9841878785f7 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_dcb.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_dcb.c
@@ -78,7 +78,7 @@ bnxt_hwrm_queue_pri2cos_cfg(struct bnxt_softc *softc,
 		qidx = softc->tc_to_qidx[ets->prio_tc[i]];
 		pri2cos[i] = q_info[qidx].queue_id;
 	}
-	return _hwrm_send_message(softc, &req, sizeof(req));
+	return hwrm_send_message(softc, &req, sizeof(req));
 }
 
 static int
@@ -92,6 +92,7 @@ bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PRI2COS_QCFG);
 
 	req.flags = htole32(HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN);
+	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
 	if (!rc) {
 		uint8_t *pri2cos = &resp->pri0_cos_queue_id;
@@ -106,6 +107,7 @@ bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets
 				ets->prio_tc[i] = tc;
 		}
 	}
+	BNXT_HWRM_UNLOCK(softc);
 	return rc;
 }
 
@@ -152,7 +154,7 @@ bnxt_hwrm_queue_cos2bw_cfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets,
 			req.unused_0 = 0;
 		}
 	}
-	return _hwrm_send_message(softc, &req, sizeof(req));
+	return hwrm_send_message(softc, &req, sizeof(req));
 }
 
 static int
@@ -167,8 +169,10 @@ bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
 
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_COS2BW_QCFG);
 
+	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
 	if (rc) {
+		BNXT_HWRM_UNLOCK(softc);
 		return rc;
 	}
 
@@ -191,6 +195,7 @@ bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
 			ets->tc_tx_bw[tc] = cos2bw.bw_weight;
 		}
 	}
+	BNXT_HWRM_UNLOCK(softc);
 	return 0;
 }
 
@@ -288,7 +293,7 @@ bnxt_hwrm_queue_pfc_cfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_CFG);
 
 	req.flags = htole32(pri_mask);
-	return _hwrm_send_message(softc, &req, sizeof(req));
+	return hwrm_send_message(softc, &req, sizeof(req));
 }
 
 static int
@@ -302,13 +307,16 @@ bnxt_hwrm_queue_pfc_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
 
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_QCFG);
 
+	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
 	if (rc) {
+		BNXT_HWRM_UNLOCK(softc);
 		return rc;
 	}
 
 	pri_mask = le32toh(resp->flags);
 	pfc->pfc_en = pri_mask;
+	BNXT_HWRM_UNLOCK(softc);
 	return 0;
 }
 
@@ -341,7 +349,7 @@ bnxt_hwrm_get_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
 	get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
 	get.count = 0;
-	rc = _hwrm_send_message(softc, &get, sizeof(get));
+	rc = hwrm_send_message(softc, &get, sizeof(get));
 	if (rc)
 		goto set_app_exit;
 
@@ -362,6 +370,11 @@ bnxt_hwrm_get_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	}
 
 set_app_exit:
+	if (rc == ETIMEDOUT) {
+		device_printf(softc->dev,
+		    "dcbx app get timed out, leaking DMA buffer\n");
+		return rc;
+	}
 	iflib_dma_free(&dma_data);
 	return rc;
 }
@@ -377,6 +390,7 @@ bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	struct iflib_dma_info dma_data;
 	size_t data_len;
 	int rc, n, i;
+	bool did_set = false;
 
 	if (softc->hwrm_spec_code < 0x10601)
 		return 0;
@@ -393,7 +407,7 @@ bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
 	get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
 	get.count = 0;
-	rc = _hwrm_send_message(softc, &get, sizeof(get));
+	rc = hwrm_send_message(softc, &get, sizeof(get));
 	if (rc)
 		goto set_app_exit;
 
@@ -445,9 +459,16 @@ bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	set.src_data_addr = htole64(dma_data.idi_paddr);
 	set.data_len = htole16(sizeof(*data) + sizeof(*fw_app) * n);
 	set.hdr_cnt = 1;
-	rc = _hwrm_send_message(softc, &set, sizeof(set));
+	did_set = true;
+	rc = hwrm_send_message(softc, &set, sizeof(set));
 
 set_app_exit:
+	if (rc == ETIMEDOUT) {
+		device_printf(softc->dev,
+		    "dcbx app %s timed out, leaking DMA buffer\n",
+		    did_set ? "set" : "get");
+		return rc;
+	}
 	iflib_dma_free(&dma_data);
 	return rc;
 }
@@ -466,12 +487,14 @@ bnxt_hwrm_queue_dscp_qcaps(struct bnxt_softc *softc)
 
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP_QCAPS);
 
+	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
 	if (!rc) {
 		softc->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
 		if (softc->max_dscp_value < 0x3f)
 			softc->max_dscp_value = 0;
 	}
+	BNXT_HWRM_UNLOCK(softc);
 	return rc;
 }
 
@@ -502,12 +525,15 @@ bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app
 	req.dest_data_addr = htole64(dma_data.idi_paddr);
 	req.dest_data_buffer_size = htole16(sizeof(*dscp2pri) * 64);
 	req.port_id = htole16(softc->pf.port_id);
+	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
+	if (!rc)
+		entry_cnt = le16toh(resp->entry_cnt);
+	BNXT_HWRM_UNLOCK(softc);
 
 	if (rc)
 		goto end;
 
-	entry_cnt =  le16toh(resp->entry_cnt);
 	for (i = 0; i < entry_cnt && *num_inputs < nitems; i++) {
 		app[*num_inputs].priority = dscp2pri[i].pri;
 		app[*num_inputs].protocol = dscp2pri[i].dscp;
@@ -516,6 +542,11 @@ bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app
 	}
 
 end:
+	if (rc == ETIMEDOUT) {
+		device_printf(softc->dev,
+		    "dscp2pri qcfg timed out, leaking DMA buffer\n");
+		return rc;
+	}
 	iflib_dma_free(&dma_data);
 	return rc;
 }
@@ -549,8 +580,13 @@ bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
 	dscp2pri->pri = app->priority;
 	req.entry_cnt = htole16(1);
 	req.port_id = htole16(softc->pf.port_id);
-	rc = _hwrm_send_message(softc, &req, sizeof(req));
+	rc = hwrm_send_message(softc, &req, sizeof(req));
 
+	if (rc == ETIMEDOUT) {
+		device_printf(softc->dev,
+		    "dscp2pri cfg timed out, leaking DMA buffer\n");
+		return rc;
+	}
 	iflib_dma_free(&dma_data);
 	return rc;
 }