git: d1619865da1c - main - if_bnxt: add support for HW generic stats
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 09 Oct 2026 10:12:50 UTC
The branch main has been updated by ssaxena:
URL: https://cgit.FreeBSD.org/src/commit/?id=d1619865da1cd4c5b557158b4bbf666e0f7f040b
commit d1619865da1cd4c5b557158b4bbf666e0f7f040b
Author: Sumit Saxena <sumit.saxena@broadcom.com>
AuthorDate: 2026-07-31 16:00:58 +0000
Commit: Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-10-09 08:24:44 +0000
if_bnxt: add support for HW generic stats
HW generic stats provide information about PCIe transactions and
out-of-order doorbell writes, useful for debug. Allocate a DMA buffer
for them (disabling BNXT_FW_CAP_GENERIC_STATS if the allocation
fails), fetch them via HWRM_STAT_GENERIC_QSTATS once per admin-status
tick on P5+ chips, and expose them to userspace under
dev.bnxt.<unit>.hwstats.generic_stats.* via sysctl.
Reviewed by: gallatin
MFC after: 2 weeks
Sponsored by: Broadcom Inc.
Differential Revision: https://reviews.freebsd.org/D58614
---
sys/dev/bnxt/bnxt_en/bnxt.h | 3 ++
sys/dev/bnxt/bnxt_en/bnxt_hwrm.c | 20 ++++++++
sys/dev/bnxt/bnxt_en/bnxt_hwrm.h | 1 +
sys/dev/bnxt/bnxt_en/bnxt_sysctl.c | 94 ++++++++++++++++++++++++++++++++++++++
sys/dev/bnxt/bnxt_en/bnxt_sysctl.h | 1 +
sys/dev/bnxt/bnxt_en/if_bnxt.c | 15 ++++++
6 files changed, 134 insertions(+)
diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index 09092cf7d59e..763748974458 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -1294,6 +1294,9 @@ struct bnxt_softc {
struct tx_port_stats_ext *tx_port_stats_ext;
struct rx_port_stats_ext *rx_port_stats_ext;
+ struct iflib_dma_info hw_generic_stats;
+ struct generic_sw_hw_stats *generic_stats;
+
uint16_t fw_rx_stats_ext_size;
uint16_t fw_tx_stats_ext_size;
uint16_t hw_ring_stats_size;
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
index 680bb593c4b4..73afb62b21ad 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
@@ -2230,6 +2230,26 @@ bnxt_hwrm_port_qstats(struct bnxt_softc *softc)
return rc;
}
+
+int bnxt_hwrm_generic_qstats(struct bnxt_softc *bp, u8 flags)
+{
+ struct hwrm_stat_generic_qstats_input req = {0};
+ int rc;
+
+ if (!(bp->fw_cap & BNXT_FW_CAP_GENERIC_STATS))
+ return 0;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_STAT_GENERIC_QSTATS);
+
+ req.flags = flags;
+ req.generic_stat_size = sizeof(struct generic_sw_hw_stats);
+ req.generic_stat_host_addr = htole64(bp->hw_generic_stats.idi_paddr);
+
+ rc = hwrm_send_message(bp, &req, sizeof(req));
+
+ return rc;
+}
+
static int bnxt_hwrm_pri2cos_idx(struct bnxt_softc *softc, uint32_t path_dir)
{
struct hwrm_queue_pri2cos_qcfg_input req = {0};
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
index 641a1e9ebe3a..e507b716303d 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt_hwrm.h
@@ -68,6 +68,7 @@ int bnxt_hwrm_stat_ctx_alloc(struct bnxt_softc *softc, struct bnxt_cp_ring *cpr,
uint64_t paddr);
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_generic_qstats(struct bnxt_softc *softc, uint8_t flags);
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);
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
index fad3982f5581..37a878c9d85f 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
@@ -336,6 +336,100 @@ bnxt_create_tx_sysctls(struct bnxt_softc *softc, int txr)
return 0;
}
+int
+bnxt_create_generic_stats_sysctls(struct bnxt_softc *softc)
+{
+ struct sysctl_oid *oid;
+ char name[32];
+ char desc[64];
+
+ sprintf(name, "generic_stats");
+ sprintf(desc, "Generic Stats");
+ oid = SYSCTL_ADD_NODE(&softc->hw_stats,
+ SYSCTL_CHILDREN(softc->hw_stats_oid), OID_AUTO, name,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, desc);
+ if (!oid)
+ return ENOMEM;
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_statistics_tx_tlp", CTLFLAG_RD,
+ &softc->generic_stats->pcie_statistics_tx_tlp, "pcie_statistics_tx_tlp");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_statistics_rx_tlp", CTLFLAG_RD,
+ &softc->generic_stats->pcie_statistics_rx_tlp, "pcie_statistics_rx_tlp");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_hdr_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_hdr_posted, "pcie_credit_fc_hdr_posted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_hdr_nonposted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_hdr_nonposted, "pcie_credit_fc_hdr_nonposted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_hdr_cmpl", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_hdr_cmpl, "pcie_credit_fc_hdr_cmpl");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_data_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_data_posted, "pcie_credit_fc_data_posted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_data_nonposted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_data_nonposted, "pcie_credit_fc_data_nonposted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_data_cmpl", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_data_cmpl, "pcie_credit_fc_data_cmpl");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_tgt_nonposted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_tgt_nonposted, "pcie_credit_fc_tgt_nonposted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_tgt_data_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_tgt_data_posted, "pcie_credit_fc_tgt_data_posted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_tgt_hdr_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_tgt_hdr_posted, "pcie_credit_fc_tgt_hdr_posted");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_cmpl_hdr_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_cmpl_hdr_posted, "pcie_credit_fc_cmpl_hdr_posted");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_credit_fc_cmpl_data_posted", CTLFLAG_RD,
+ &softc->generic_stats->pcie_credit_fc_cmpl_data_posted, "pcie_credit_fc_cmpl_data_posted");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_cmpl_longest", CTLFLAG_RD,
+ &softc->generic_stats->pcie_cmpl_longest, "pcie_cmpl_longest");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "pcie_cmpl_shortest", CTLFLAG_RD,
+ &softc->generic_stats->pcie_cmpl_shortest, "pcie_cmpl_shortest");
+
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "cache_miss_count_cfcq", CTLFLAG_RD,
+ &softc->generic_stats->cache_miss_count_cfcq, "cache_miss_count_cfcq");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "cache_miss_count_cfcs", CTLFLAG_RD,
+ &softc->generic_stats->cache_miss_count_cfcs, "cache_miss_count_cfcs");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "cache_miss_count_cfcc", CTLFLAG_RD,
+ &softc->generic_stats->cache_miss_count_cfcc, "cache_miss_count_cfcc");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "cache_miss_count_cfcm", CTLFLAG_RD,
+ &softc->generic_stats->cache_miss_count_cfcm, "cache_miss_count_cfcm");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "hw_db_recov_dbs_dropped", CTLFLAG_RD,
+ &softc->generic_stats->hw_db_recov_dbs_dropped, "hw_db_recov_dbs_dropped");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "hw_db_recov_drops_serviced", CTLFLAG_RD,
+ &softc->generic_stats->hw_db_recov_drops_serviced, "hw_db_recov_drops_serviced");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "hw_db_recov_dbs_recovered", CTLFLAG_RD,
+ &softc->generic_stats->hw_db_recov_dbs_recovered, "hw_db_recov_dbs_recovered");
+ SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ "hw_db_recov_oo_drop_count", CTLFLAG_RD,
+ &softc->generic_stats->hw_db_recov_oo_drop_count, "hw_db_recov_oo_drop_count");
+
+ return 0;
+}
+
int
bnxt_create_port_stats_sysctls(struct bnxt_softc *softc)
{
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.h b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
index 317cf06ae4b2..2a4531c69779 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
@@ -32,6 +32,7 @@
int bnxt_init_sysctl_ctx(struct bnxt_softc *softc);
int bnxt_free_sysctl_ctx(struct bnxt_softc *softc);
int bnxt_create_port_stats_sysctls(struct bnxt_softc *softc);
+int bnxt_create_generic_stats_sysctls(struct bnxt_softc *softc);
int bnxt_create_tx_sysctls(struct bnxt_softc *softc, int txr);
int bnxt_create_rx_sysctls(struct bnxt_softc *softc, int rxr);
int bnxt_create_ver_sysctls(struct bnxt_softc *softc);
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 6566c1e8f442..e0e606189fdb 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -735,6 +735,7 @@ bnxt_queues_free(if_ctx_t ctx)
// Free RX queues
for (i=0; i<softc->nrxqsets; i++)
iflib_dma_free(&softc->rx_stats[i]);
+ iflib_dma_free(&softc->hw_generic_stats);
iflib_dma_free(&softc->hw_tx_port_stats);
iflib_dma_free(&softc->hw_rx_port_stats);
iflib_dma_free(&softc->hw_tx_port_stats_ext);
@@ -808,6 +809,17 @@ bnxt_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
*/
#define BNXT_PORT_STAT_PADDING 512
+ rc = iflib_dma_alloc(ctx, sizeof(struct generic_sw_hw_stats), &softc->hw_generic_stats, 0);
+ /* Generic stats are optional */
+ if (rc) {
+ softc->fw_cap &= ~BNXT_FW_CAP_GENERIC_STATS;
+ iflib_dma_free(&softc->hw_generic_stats);
+ } else {
+ bus_dmamap_sync(softc->hw_generic_stats.idi_tag,
+ softc->hw_generic_stats.idi_map, BUS_DMASYNC_PREREAD);
+ softc->generic_stats = (void *) softc->hw_generic_stats.idi_vaddr;
+ }
+
rc = iflib_dma_alloc(ctx, sizeof(struct rx_port_stats) + BNXT_PORT_STAT_PADDING,
&softc->hw_rx_port_stats, 0);
if (rc)
@@ -916,6 +928,7 @@ bnxt_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs,
bnxt_create_rx_sysctls(softc, i);
}
+ bnxt_create_generic_stats_sysctls(softc);
/*
* When SR-IOV is enabled, avoid each VF sending PORT_QSTATS
* HWRM every sec with which firmware timeouts can happen
@@ -4256,6 +4269,8 @@ bnxt_update_admin_status(if_ctx_t ctx)
bit_clear(softc->state_bv, BNXT_STATE_LINK_CHANGE);
bnxt_media_status(softc->ctx, &ifmr);
}
+
+ bnxt_hwrm_generic_qstats(softc, 0);
}
return;