git: ed1f24d3e1a1 - main - if_bnxt: drop epoch_arr[] to detect EPOCH bit toggle

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

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

commit ed1f24d3e1a1c0f85bf3eda0337cfbf76bc34cf6
Author:     Sumit Saxena <sumit.saxena@broadcom.com>
AuthorDate: 2026-08-03 05:03:22 +0000
Commit:     Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-10-09 08:24:45 +0000

    if_bnxt: drop epoch_arr[] to detect EPOCH bit toggle
    
    The EPOCH array size is 4096 but the driver does not enforce any limit
    on ring size, so setting ring size >4096 corrupts adjacent memory
    and leads to undefined behavior.
    
    Toggle epoch_bit directly at every ring-producer wrap point (TX/RX
    encap and refill, MPC crypto commands, kTLS presync/replay) instead of
    looking it up per-index in the doorbell path, dropping the now-unused
    epoch_arr[] snapshot array.
    
    Reported by:    gallatin
    Reviewed by:    gallatin
    MFC after:      2 weeks
    Sponsored by:   Broadcom Inc.
    Differential Revision:  https://reviews.freebsd.org/D58620
    Change-Id: I4673d64670ee0e8ea256b8a8932724bbd73f710d
---
 sys/dev/bnxt/bnxt_en/bnxt.h      |  3 ---
 sys/dev/bnxt/bnxt_en/bnxt_ktls.c | 24 ++++++++++++++++++------
 sys/dev/bnxt/bnxt_en/bnxt_mpc.c  |  5 +++++
 sys/dev/bnxt/bnxt_en/bnxt_txrx.c | 26 ++++----------------------
 sys/dev/bnxt/bnxt_en/if_bnxt.c   |  4 ++--
 5 files changed, 29 insertions(+), 33 deletions(-)

diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index 14f17b6d288a..e8ffc9fdb057 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -606,8 +606,6 @@ struct bnxt_grp_info {
 	uint16_t	ag_ring_id;
 };
 
-#define	EPOCH_ARR_SZ	4096
-
 struct tx_bd_opaque {
 	uint16_t idx;
 	uint16_t bds:15,
@@ -690,7 +688,6 @@ struct bnxt_ring {
 	uint32_t                db_epoch_mask;
 	uint8_t                 db_epoch_shift;
 
-	uint64_t		epoch_arr[EPOCH_ARR_SZ];
 	bool                    epoch_bit;
 
 };
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_ktls.c b/sys/dev/bnxt/bnxt_en/bnxt_ktls.c
index 90c59607f336..31549707d275 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_ktls.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_ktls.c
@@ -1655,6 +1655,8 @@ static int bnxt_ktls_submit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr
 	}
 
 	prod = RING_NEXT(txr, prod);
+	if (prod == 0)
+		txr->epoch_bit = !txr->epoch_bit;
 
 	if (pi->ipi_tso_segsz != 0) {
 		/* Preserve the connection's actual negotiated MSS. */
@@ -1711,6 +1713,8 @@ static int bnxt_ktls_submit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr
 		tbd->flags_type = htole16(flags_type);
 
 		prod = RING_NEXT(txr, prod);
+		if (prod == 0)
+			txr->epoch_bit = !txr->epoch_bit;
 
 		tbd = &((struct tx_bd_long *)txr->vaddr)[prod];
 		tbd->len = htole16(segs[seg].ds_len);
@@ -1722,6 +1726,8 @@ static int bnxt_ktls_submit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr
 	tbd->flags_type = htole16(flags_type);
 
 	prod = RING_NEXT(txr, prod);
+	if (prod == 0)
+		txr->epoch_bit = !txr->epoch_bit;
 
 	txr->prod = prod;
 
@@ -1773,6 +1779,8 @@ static void bnxt_ktls_pre_xmit(struct bnxt_softc *bp, struct bnxt_ring *txr,
 	}
 
 	prod = RING_NEXT(txr, prod);
+	if (prod == 0)
+		txr->epoch_bit = !txr->epoch_bit;
 
 	/* Copy pre-cmd to TX desc ring*/
 	pcmd1 = &((struct tx_bd *)txr->vaddr)[prod];
@@ -1785,6 +1793,7 @@ static void bnxt_ktls_pre_xmit(struct bnxt_softc *bp, struct bnxt_ring *txr,
 	} else {
 		memcpy(pcmd, pre_cmd, space);
 		prod = 0;
+		txr->epoch_bit = !txr->epoch_bit;
 		pcmd1 = &((struct tx_bd *)txr->vaddr)[prod];
 		pcmd = (uint8_t *)pcmd1;
 		memcpy((uint8_t *)pcmd, (uint8_t *)pre_cmd + space,
@@ -1793,6 +1802,8 @@ static void bnxt_ktls_pre_xmit(struct bnxt_softc *bp, struct bnxt_ring *txr,
 	}
 
 	prod = RING_NEXT(txr, prod);
+	if (prod == 0)
+		txr->epoch_bit = !txr->epoch_bit;
 	tx_buf->inline_bds = CRYPTO_PREFIX_CMD_BDS - 1;
 	txr->prod = prod;
 }
@@ -1952,6 +1963,7 @@ static int bnxt_ktls_tx_ooo(struct bnxt_softc *bp, struct bnxt_ring *txr,
 	bool update_inorder = false;
 	uint32_t tx_prod;
 	uint16_t running_bds;
+	bool epoch_bit;
 
 	ktls = bp->ktls_info;
 
@@ -2031,13 +2043,12 @@ static int bnxt_ktls_tx_ooo(struct bnxt_softc *bp, struct bnxt_ring *txr,
 	pcmd.flags = htole32(presync_flags);
 
 	/*
-	 * Save tx ring producer index and running_bds accumulator before
-	 * writing presync command, it will be used to move the producer
-	 * index backwards to discard presync command and restore running_bds
-	 * to the state of before sending presync command, if replay packet fails.
+	 * Save producer/running_bds/epoch_bit before the presync command so
+	 * they can be rolled back if the replay packet fails to post.
 	 */
 	tx_prod = txr->prod;
 	running_bds = txr->running_bds;
+	epoch_bit = txr->epoch_bit;
 
 	bnxt_ktls_pre_xmit(bp, txr, kctx_tx->kid, &pcmd);
 
@@ -2047,12 +2058,13 @@ static int bnxt_ktls_tx_ooo(struct bnxt_softc *bp, struct bnxt_ring *txr,
 		if (fwd)
 			counter_u64_add(ktls->counters[BNXT_KTLS_TX_SEQ_FWD_REPLAY], 1);
 		/*
-		 * If replay failed, discard presync BD by rolling back both the
-		 * producer index and restore running_bds accumulator.
+		 * If replay failed, discard presync BD by rolling back the
+		 * producer index, running_bds accumulator, and epoch_bit.
 		 */
 		if (rc) {
 			txr->prod = tx_prod;
 			txr->running_bds = running_bds;
+			txr->epoch_bit = epoch_bit;
 		}
 	}
 
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_mpc.c b/sys/dev/bnxt/bnxt_en/bnxt_mpc.c
index 4e35b3bdca9c..1182a5baede5 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_mpc.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_mpc.c
@@ -564,6 +564,7 @@ int bnxt_hwrm_mpc_ring_alloc(struct bnxt_softc *softc)
 
 			txr->prod = 0;
 			txr->cons = 0;
+			txr->epoch_bit = false;
 			memset(txr->tx_mpc_buf_ring, 0,
 			    txr->ring_size * sizeof(struct bnxt_sw_mpc_tx_bd));
 
@@ -874,6 +875,10 @@ int bnxt_start_xmit_mpc(struct bnxt_softc *softc, struct bnxt_ring *txr,
 		return EBUSY;
 
 	prod = txr->prod;
+	/* Wraps the ring at most once since total_bds < ring_size; toggle
+	 * epoch_bit to match, as prod advances directly here, not per-BD. */
+	if ((uint32_t)prod + total_bds >= txr->ring_size)
+		txr->epoch_bit = !txr->epoch_bit;
 	txbd = &((struct tx_bd_long *)txr->vaddr)[prod];
 
 	tx_buf = &txr->tx_mpc_buf_ring[prod];
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_txrx.c b/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
index 72de950bea0d..c621300ad877 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
@@ -103,7 +103,6 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
 	uint16_t lflags = 0;
 	uint32_t cfa_meta;
 	int seg = 0;
-	uint8_t wrap = 0;
 	struct tx_bd_opaque *opq;
 
 	txr->prod = pi->ipi_pidx;
@@ -170,17 +169,9 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
 	if (need_hi) {
 		flags_type |= TX_BD_LONG_TYPE_TX_BD_LONG;
 
-		/* Handle wrapping */
-		if (pi->ipi_new_pidx == txr->ring_size - 1)
-			wrap = 1;
-
 		pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx);
-
-		/* Toggle epoch bit on wrap */
-		if (wrap && pi->ipi_new_pidx == 0)
+		if (pi->ipi_new_pidx == 0)
 			txr->epoch_bit = !txr->epoch_bit;
-		if (pi->ipi_new_pidx < EPOCH_ARR_SZ)
-			txr->epoch_arr[pi->ipi_new_pidx] = txr->epoch_bit;
 
 		tbdh = &((struct tx_bd_long_hi *)txr->vaddr)[pi->ipi_new_pidx];
 #ifdef KTLS_IFLIB_SUPPORT
@@ -236,13 +227,9 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
 	for (; seg < pi->ipi_nsegs; seg++) {
 		tbd->flags_type = htole16(flags_type);
 
-		if (pi->ipi_new_pidx == txr->ring_size - 1)
-			wrap = 1;
 		pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx);
-		if (wrap && pi->ipi_new_pidx == 0)
+		if (pi->ipi_new_pidx == 0)
 			txr->epoch_bit = !txr->epoch_bit;
-		if (pi->ipi_new_pidx < EPOCH_ARR_SZ)
-			txr->epoch_arr[pi->ipi_new_pidx] = txr->epoch_bit;
 
 		tbd = &((struct tx_bd_long *)txr->vaddr)[pi->ipi_new_pidx];
 		tbd->len = htole16(pi->ipi_segs[seg].ds_len);
@@ -251,13 +238,10 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
 	}
 	flags_type |= TX_BD_SHORT_FLAGS_PACKET_END;
 	tbd->flags_type = htole16(flags_type);
-	if (pi->ipi_new_pidx == txr->ring_size - 1)
-		wrap = 1;
+
 	pi->ipi_new_pidx = RING_NEXT(txr, pi->ipi_new_pidx);
-	if (wrap && pi->ipi_new_pidx == 0)
+	if (pi->ipi_new_pidx == 0)
 		txr->epoch_bit = !txr->epoch_bit;
-	if (pi->ipi_new_pidx < EPOCH_ARR_SZ)
-		txr->epoch_arr[pi->ipi_new_pidx] = txr->epoch_bit;
 
 	txr->prod = pi->ipi_new_pidx;
 	return 0;
@@ -451,8 +435,6 @@ bnxt_isc_rxd_refill(void *sc, if_rxd_update_t iru)
 			pidx = 0;
 			rx_ring->epoch_bit = !rx_ring->epoch_bit;
 		}
-		if (pidx < EPOCH_ARR_SZ)
-			rx_ring->epoch_arr[pidx] = rx_ring->epoch_bit;
 	}
 
 	return;
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 0c0f896f2c12..0757985fa49f 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -1714,7 +1714,7 @@ bnxt_thor2_db_rx(void *db_ptr, uint16_t idx)
 				((uint64_t)ring->phys_id << DBR_XID_SFT));
 
 	/* Add the PI index */
-	db_val |= DB_RING_IDX(ring, idx, ring->epoch_arr[idx]);
+	db_val |= DB_RING_IDX(ring, idx, ring->epoch_bit);
 
 	bus_space_barrier(db_bar->tag, db_bar->handle, ring->doorbell, 8,
 			BUS_SPACE_BARRIER_WRITE);
@@ -1738,7 +1738,7 @@ bnxt_thor2_db_tx(void *db_ptr, uint16_t idx)
 				((uint64_t)ring->phys_id << DBR_XID_SFT));
 
 	/* Add the PI index */
-	db_val |= DB_RING_IDX(ring, idx, ring->epoch_arr[idx]);
+	db_val |= DB_RING_IDX(ring, idx, ring->epoch_bit);
 
 	bus_space_barrier(db_bar->tag, db_bar->handle, ring->doorbell, 8,
 			BUS_SPACE_BARRIER_WRITE);