git: 3c995919dc4a - main - if_bnxt: add host-based TX completion coalescing
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 09 Oct 2026 10:12:34 UTC
The branch main has been updated by ssaxena:
URL: https://cgit.FreeBSD.org/src/commit/?id=3c995919dc4a7f5de35534b3220f972bf0153fb9
commit 3c995919dc4a7f5de35534b3220f972bf0153fb9
Author: Sumit Saxena <sumit.saxena@broadcom.com>
AuthorDate: 2026-08-03 09:07:36 +0000
Commit: Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-10-09 08:24:42 +0000
if_bnxt: add host-based TX completion coalescing
Suppress per-BD completions (TX_BD_LONG_FLAGS_NO_CMPL/_COAL_NOW) and
accumulate a running_bds count per ring, forcing a real completion
when iflib requests one or when the count nears overflowing the
opaque bd-count field. Replaces the previous raw (bd_count << 24 |
idx) TX completion opaque encoding, which only had 8 bits for the
count and would overflow well within these coalescing thresholds,
with a tx_bd_opaque bitfield (16-bit idx + 15-bit bds + 1-bit
ktls_replay for later use). Add tx_host_coal_bds/tx_host_coal_enable
sysctls to tune and toggle it.
Reviewed by: gallatin
MFC after: 2 weeks
Sponsored by: Broadcom Inc.
Differential Revision: https://reviews.freebsd.org/D58600
---
sys/dev/bnxt/bnxt_en/bnxt.h | 22 +++++++++++++++++++
sys/dev/bnxt/bnxt_en/bnxt_sysctl.c | 44 ++++++++++++++++++++++++++++++++++++++
sys/dev/bnxt/bnxt_en/bnxt_txrx.c | 32 +++++++++++++++++++++++++--
sys/dev/bnxt/bnxt_en/if_bnxt.c | 7 ++++++
4 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index ac91661eda7f..80cc8905d66b 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -600,6 +600,14 @@ struct bnxt_grp_info {
#define EPOCH_ARR_SZ 4096
+struct tx_bd_opaque {
+ uint16_t idx;
+ uint16_t bds:15,
+ ktls_replay:1;
+} __packed;
+
+#define TX_RING_MASK(txr) ((txr)->ring_size - 1)
+
struct bnxt_ring {
uint64_t paddr;
vm_offset_t doorbell;
@@ -609,6 +617,7 @@ struct bnxt_ring {
uint16_t id; /* Logical ID */
uint16_t phys_id;
uint16_t idx;
+ uint16_t running_bds; /* host TX-completion-coalescing accumulator */
struct bnxt_full_tpa_start *tpa_start;
union {
u64 db_key64;
@@ -1433,6 +1442,19 @@ struct bnxt_softc {
#define BNXT_CAGR_TICK_RES_MAX 0x4
#define BNXT_CAGR_TICK_RES_OFFSET 16
uint32_t cagr_tick_res;
+
+ /* Matches this branch's scctx->isc_tx_nsegments; cached for the
+ * tx_host_coal_bds underflow guard below. */
+#define BNXT_MAX_NUM_SEGS 31
+ uint32_t tx_ring_size; /* cached scctx->isc_ntxd[1] */
+ /*
+ * Host-based TX coalescing: driver suppresses per-BD completions by
+ * setting TX_BD_LONG_FLAGS_NO_CMPL / TX_BD_LONG_FLAGS_COAL_NOW on BDs.
+ */
+#define BNXT_TX_HOST_COAL_BDS_MIN 33 /* must be > BNXT_MAX_NUM_SEGS+1 to avoid uint underflow */
+#define BNXT_TX_HOST_COAL_BDS_DEFAULT 256 /* cap for large rings; halved for small rings */
+ uint32_t tx_host_coal_bds; /* max BDs before forcing completion */
+ bool tx_host_coal_enable; /* enable host-driven TX coalescing */
/* Firmware coalesces completions autonomously based on cmpl_coal_cnt
* (only valid when BNXT_FLAG_TX_COAL_CMPL is set); raw codes map to
* counts 4,8,12,16,24,32,48,64,96,128,192,256,320,384,MAX. */
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
index 729d0aa1f5c7..cfe57cf25c2c 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
@@ -1580,6 +1580,30 @@ bnxt_set_cagr_tick_res(SYSCTL_HANDLER_ARGS) {
return rc;
}
+static int
+bnxt_set_tx_host_coal_bds(SYSCTL_HANDLER_ARGS)
+{
+ struct bnxt_softc *softc = arg1;
+ uint32_t val;
+ int rc;
+
+ if (softc == NULL)
+ return EBUSY;
+
+ val = softc->tx_host_coal_bds;
+
+ rc = sysctl_handle_int(oidp, (int *)&val, 0, req);
+ if (rc || !req->newptr)
+ return rc;
+
+ if (val < BNXT_TX_HOST_COAL_BDS_MIN || val > softc->tx_ring_size)
+ return EINVAL;
+
+ softc->tx_host_coal_bds = val;
+
+ return 0;
+}
+
static int
bnxt_set_tx_hw_coal_cnt(SYSCTL_HANDLER_ARGS)
{
@@ -1700,7 +1724,27 @@ bnxt_create_config_sysctls_pre(struct bnxt_softc *softc)
CTLTYPE_INT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, softc, 0,
bnxt_set_cagr_tick_res, "I", "CAGR tick resolution");
+ /*
+ * Default coal_bds to half the Tx ring depth, clamped between
+ * BNXT_TX_HOST_COAL_BDS_MIN and DEFAULT; disable below the floor to
+ * avoid uint underflow in (coal_bds - (BNXT_MAX_NUM_SEGS+1)).
+ */
+ softc->tx_host_coal_bds = min(softc->tx_ring_size,
+ max(BNXT_TX_HOST_COAL_BDS_MIN,
+ min(BNXT_TX_HOST_COAL_BDS_DEFAULT, softc->tx_ring_size / 2)));
+ softc->tx_host_coal_enable =
+ (softc->tx_ring_size >= BNXT_TX_HOST_COAL_BDS_MIN);
softc->tx_hw_coal_cnt = BNXT_TX_HW_COAL_CNT_DEFAULT;
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_host_coal_bds",
+ CTLTYPE_INT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, softc, 0,
+ bnxt_set_tx_host_coal_bds, "I",
+ "host-driven TX coalescing: max BDs before forcing completion "
+ "(33 to Tx ring size, default max(33, min(256, ring_size/2)) "
+ "clamped to ring_size; feature auto-disabled if ring_size < 33)");
+ SYSCTL_ADD_BOOL(ctx, children, OID_AUTO, "tx_host_coal_enable", CTLFLAG_RDTUN,
+ &softc->tx_host_coal_enable, 0,
+ "enable host-driven TX coalescing via NO_CMPL/COAL_NOW BD flags "
+ "(default enabled)");
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_hw_coal_cnt",
CTLTYPE_INT | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, softc, 0,
bnxt_set_tx_hw_coal_cnt, "I",
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_txrx.c b/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
index 40b02744c6c1..430913c61547 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_txrx.c
@@ -94,12 +94,24 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
struct bnxt_ring *txr = &softc->tx_rings[pi->ipi_qsidx];
struct tx_bd_long *tbd;
struct tx_bd_long_hi *tbdh;
+ bool need_cpl = false;
bool need_hi = false;
uint16_t flags_type;
uint16_t lflags;
uint32_t cfa_meta;
int seg = 0;
uint8_t wrap = 0;
+ struct tx_bd_opaque *opq;
+
+ if ((pi->ipi_flags & IPI_TX_INTR) != 0)
+ need_cpl = true;
+
+ if (softc->tx_host_coal_enable) {
+ /* BD field of opaque is only 15 bits; respect tx_host_coal_bds threshold */
+ if (txr->running_bds >
+ (softc->tx_host_coal_bds - (BNXT_MAX_NUM_SEGS + 1)))
+ need_cpl = true;
+ }
/* If we have offloads enabled, we need to use two BDs. */
if ((pi->ipi_csum_flags & (CSUM_OFFLOAD | CSUM_TSO | CSUM_IP)) ||
@@ -112,12 +124,26 @@ bnxt_isc_txd_encap(void *sc, if_pkt_info_t pi)
pi->ipi_new_pidx = pi->ipi_pidx;
tbd = &((struct tx_bd_long *)txr->vaddr)[pi->ipi_new_pidx];
pi->ipi_ndescs = 0;
+ opq = (struct tx_bd_opaque *)&tbd->opaque;
/* No need to byte-swap the opaque value */
- tbd->opaque = ((pi->ipi_nsegs + need_hi) << 24) | pi->ipi_new_pidx;
+ opq->ktls_replay = 0;
+ opq->idx = pi->ipi_new_pidx & TX_RING_MASK(txr);
+ opq->bds = txr->running_bds + pi->ipi_nsegs + need_hi;
tbd->len = htole16(pi->ipi_segs[seg].ds_len);
tbd->addr = htole64(pi->ipi_segs[seg++].ds_addr);
flags_type = ((pi->ipi_nsegs + need_hi) <<
TX_BD_SHORT_FLAGS_BD_CNT_SFT) & TX_BD_SHORT_FLAGS_BD_CNT_MASK;
+
+ if (softc->tx_host_coal_enable) {
+ flags_type |= TX_BD_LONG_FLAGS_COAL_NOW;
+ if (need_cpl)
+ txr->running_bds = 0;
+ else {
+ txr->running_bds += (pi->ipi_nsegs + 1);
+ flags_type |= TX_BD_LONG_FLAGS_NO_CMPL;
+ }
+ }
+
if (pi->ipi_len >= 2048)
flags_type |= TX_BD_SHORT_FLAGS_LHINT_GTE2K;
else
@@ -235,6 +261,7 @@ bnxt_isc_txd_credits_update(void *sc, uint16_t txqid, bool clear)
uint32_t last_raw_cons;
uint16_t type;
uint16_t err;
+ struct tx_bd_opaque *opq;
for (;;) {
last_cons = cons;
@@ -258,7 +285,8 @@ bnxt_isc_txd_credits_update(void *sc, uint16_t txqid, bool clear)
device_printf(softc->dev,
"TX completion error %u\n", err);
/* No need to byte-swap the opaque value */
- avail += cmpl[cons].opaque >> 24;
+ opq = (struct tx_bd_opaque *)&cmpl[cons].opaque;
+ avail += opq->bds;
/*
* If we're not clearing, iflib only cares if there's
* at least one buffer. Don't scan the whole ring in
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 512afb450494..098fb0685dd3 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -2913,6 +2913,13 @@ bnxt_attach_pre(if_ctx_t ctx)
HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_TCP_IPV6 |
HWRM_VNIC_RSS_CFG_INPUT_HASH_TYPE_UDP_IPV6;
+ /*
+ * Cache the Tx BD ring size so sysctl validators (e.g.
+ * tx_host_coal_bds) can compare against it before per-queue
+ * tx_rings[i].ring_size has been populated.
+ */
+ softc->tx_ring_size = scctx->isc_ntxd[1];
+
if (BNXT_CHIP_P7(softc))
softc->cagr_tick_res = BNXT_CAGR_TICK_RES_DEFAULT;