git: 2c379efd1834 - main - bnxt: Report SR-IOV VF status

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 22:53:41 UTC
The branch main has been updated by kbowling:

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

commit 2c379efd1834dac2432a98de847b79f345f66974
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-08 17:46:27 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-10-30 22:53:03 +0000

    bnxt: Report SR-IOV VF status
    
    Expose the PF-known effective per-VF MAC, allocated transmit and receive
    queue counts, and policy state through the iflib VF status method.
    Snapshot the state under the SR-IOV lock so concurrent trust and
    anti-spoof sysctl updates cannot produce a torn report.  Mark known queue
    allocations present even when their value is zero.
    
    Cache a VF-selected MAC only after firmware accepts the forwarded
    request.  Prefer that address in status.  Replay the accepted address,
    trust state, and MAC anti-spoof policy after firmware recovery.
    
    Record completion of the per-VF configuration callback separately from
    firmware resource allocation.
    
    Track successful PCI SR-IOV attachment independently of the active VF
    count.  This lets a supported but unconfigured PF return an empty status
    while unsupported devices and failed attachments omit it.
    
    Sponsored by:   BBOX.io
    Differential Revision:  https://reviews.freebsd.org/D58738
---
 sys/dev/bnxt/bnxt_en/bnxt.h       |   1 +
 sys/dev/bnxt/bnxt_en/bnxt_sriov.c | 163 +++++++++++++++++++++++++++++++++-----
 sys/dev/bnxt/bnxt_en/bnxt_sriov.h |   3 +
 sys/dev/bnxt/bnxt_en/if_bnxt.c    |   1 +
 4 files changed, 150 insertions(+), 18 deletions(-)

diff --git a/sys/dev/bnxt/bnxt_en/bnxt.h b/sys/dev/bnxt/bnxt_en/bnxt.h
index 847967853cd3..07108cec9f98 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt.h
@@ -541,6 +541,7 @@ struct bnxt_pf_info {
 	uint16_t	active_vfs;
 	uint16_t	registered_vfs;
 	uint16_t	max_vfs;
+	bool		iov_attached;
 	uint16_t	max_msix_vfs;
 	uint32_t	max_encap_records;
 	uint32_t	max_decap_records;
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
index ac3c8d2d780f..8495b2843ff2 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
@@ -16,6 +16,8 @@ __FBSDID("$FreeBSD$");
 
 #ifdef PCI_IOV
 
+#include <net/if_vf_status.h>
+
 static inline bool
 bnxt_eth_addr_valid(const uint8_t *addr)
 {
@@ -97,28 +99,127 @@ bnxt_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
 {
 	struct bnxt_softc *softc = iflib_get_softc(ctx);
 	struct bnxt_vf_info *vf = &softc->pf.vf[vfnum];
+	uint8_t admin_mac[ETHER_ADDR_LEN];
+	bool has_admin_mac;
 	int rc;
 
+	BNXT_SRIOV_LOCK(softc);
 	vf->fw_fid = softc->pf.first_vf_id + vfnum;
 	vf->vfnum = vfnum;
+	has_admin_mac = bnxt_vf_parse_schema(softc, vf, params);
+	memcpy(admin_mac, vf->mac_addr, sizeof(admin_mac));
+	BNXT_SRIOV_UNLOCK(softc);
 
 	/*
 	 * If the schema provided a valid admin MAC, program it into firmware.
 	 */
-	if (bnxt_vf_parse_schema(softc, vf, params)) {
-		rc = bnxt_set_vf_admin_mac(softc, vf, vf->mac_addr);
-		if (rc)
+	if (has_admin_mac) {
+		rc = bnxt_set_vf_admin_mac(softc, vf, admin_mac);
+		if (rc) {
 			device_printf(softc->dev,
 				      "vf%u: PF-assigned MAC programming failed (rc=%d), falling back to firmware/default MAC\n",
 				      vfnum, rc);
+			BNXT_SRIOV_LOCK(softc);
+			memset(vf->mac_addr, 0, ETHER_ADDR_LEN);
+			BNXT_SRIOV_UNLOCK(softc);
+		}
 	}
 
 	(void)bnxt_set_vf_trust(softc, vfnum, vf->trusted);
 	(void)bnxt_set_vf_spoofchk(softc, vfnum, vf->spoofchk);
 
+	BNXT_SRIOV_LOCK(softc);
+	if (softc->pf.num_vfs != 0 && vfnum < softc->pf.num_vfs)
+		softc->pf.vf[vfnum].configured = true;
+	BNXT_SRIOV_UNLOCK(softc);
+
 	return 0;
 }
 
+int
+bnxt_vf_status(if_ctx_t ctx, struct if_vf_status **statusp)
+{
+	struct bnxt_vf_status {
+		u8 mac[ETHER_ADDR_LEN];
+		u16 tx_queue_count;
+		u16 rx_queue_count;
+		bool mac_valid;
+		bool configured;
+		bool allow_set_mac;
+		bool mac_anti_spoof;
+		bool allow_promisc;
+	} snapshot[BNXT_MAX_VFS];
+	struct bnxt_softc *softc;
+	struct bnxt_vf_info *vf;
+	struct if_vf_info *info;
+	struct if_vf_status *status;
+	u16 num_vfs;
+	int i;
+
+	softc = iflib_get_softc(ctx);
+	/* The iflib context lock serializes this with IOV init and uninit. */
+	if (!BNXT_PF(softc) || !softc->pf.iov_attached)
+		return (EOPNOTSUPP);
+	if (softc->pf.num_vfs == 0) {
+		status = if_vf_status_alloc(0);
+		if (status == NULL)
+			return (ENOMEM);
+		*statusp = status;
+		return (0);
+	}
+	BNXT_SRIOV_LOCK(softc);
+	num_vfs = softc->pf.num_vfs;
+	MPASS(num_vfs <= BNXT_MAX_VFS);
+	memset(snapshot, 0, sizeof(snapshot));
+	for (i = 0; i < num_vfs; i++) {
+		vf = &softc->pf.vf[i];
+		if (bnxt_eth_addr_valid(vf->vf_mac_addr)) {
+			memcpy(snapshot[i].mac, vf->vf_mac_addr,
+			    ETHER_ADDR_LEN);
+			snapshot[i].mac_valid = true;
+		} else if (bnxt_eth_addr_valid(vf->mac_addr)) {
+			memcpy(snapshot[i].mac, vf->mac_addr, ETHER_ADDR_LEN);
+			snapshot[i].mac_valid = true;
+		}
+		snapshot[i].tx_queue_count = vf->min_tx_rings;
+		snapshot[i].rx_queue_count = vf->min_rx_rings;
+		snapshot[i].configured = vf->configured;
+		snapshot[i].allow_set_mac =
+		    (vf->flags & BNXT_VF_TRUST) != 0 ||
+		    !bnxt_eth_addr_valid(vf->mac_addr);
+		snapshot[i].mac_anti_spoof =
+		    (vf->flags & BNXT_VF_SPOOFCHK) != 0;
+		snapshot[i].allow_promisc =
+		    (vf->flags & BNXT_VF_TRUST) != 0;
+	}
+	BNXT_SRIOV_UNLOCK(softc);
+
+	status = if_vf_status_alloc(num_vfs);
+	if (status == NULL)
+		return (ENOMEM);
+	for (i = 0; i < num_vfs; i++) {
+		info = &status->vfs[i];
+		info->fields = IFVF_F_CONFIGURED | IFVF_F_ALLOW_SET_MAC |
+		    IFVF_F_MAC_ANTI_SPOOF |
+		    IFVF_F_ALLOW_PROMISC;
+		info->index = i;
+		info->configured = snapshot[i].configured;
+		if (snapshot[i].mac_valid) {
+			memcpy(info->mac, snapshot[i].mac, sizeof(info->mac));
+			info->fields |= IFVF_F_MAC;
+		}
+		info->tx_queue_count = snapshot[i].tx_queue_count;
+		info->rx_queue_count = snapshot[i].rx_queue_count;
+		info->fields |= IFVF_F_NUM_TX_QUEUES |
+		    IFVF_F_NUM_RX_QUEUES;
+		info->allow_set_mac = snapshot[i].allow_set_mac;
+		info->mac_anti_spoof = snapshot[i].mac_anti_spoof;
+		info->allow_promisc = snapshot[i].allow_promisc;
+	}
+	*statusp = status;
+	return (0);
+}
+
 /* Free driver-side VF resources (called after hwrm_vf_resc_free) */
 void bnxt_free_vf_resources(struct bnxt_softc *softc)
 {
@@ -212,16 +313,22 @@ static int bnxt_set_vf_params(struct bnxt_softc *softc, int vf_id)
 {
 	struct hwrm_func_cfg_input req = {0};
 	struct bnxt_vf_info *vf;
+	u32 flags;
 	int rc;
 
 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
 
+	BNXT_SRIOV_LOCK(softc);
 	vf = &softc->pf.vf[vf_id];
 	req.fid = htole16(vf->fw_fid);
 
-
-	if (bnxt_eth_addr_valid(vf->mac_addr)) {
-		req.enables |= htole32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
+	if (bnxt_eth_addr_valid(vf->vf_mac_addr)) {
+		req.enables |= htole32(
+		    HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
+		memcpy(req.dflt_mac_addr, vf->vf_mac_addr, ETHER_ADDR_LEN);
+	} else if (bnxt_eth_addr_valid(vf->mac_addr)) {
+		req.enables |= htole32(
+		    HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
 		memcpy(req.dflt_mac_addr, vf->mac_addr, ETHER_ADDR_LEN);
 	}
 
@@ -230,8 +337,19 @@ static int bnxt_set_vf_params(struct bnxt_softc *softc, int vf_id)
 		req.dflt_vlan = htole16(vf->vlan);
 	}
 
-	if (vf->flags & BNXT_VF_TRUST)
-		req.flags = htole32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);
+	flags = 0;
+	if (softc->fw_cap & BNXT_FW_CAP_TRUSTED_VF) {
+		flags |= vf->flags & BNXT_VF_TRUST ?
+		    HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE :
+		    HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_DISABLE;
+	}
+	if (softc->hwrm_spec_code >= 0x10701) {
+		flags |= vf->flags & BNXT_VF_SPOOFCHK ?
+		    HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE :
+		    HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE;
+	}
+	BNXT_SRIOV_UNLOCK(softc);
+	req.flags = htole32(flags);
 
 	BNXT_HWRM_LOCK(softc);
 	rc = _hwrm_send_message(softc, &req, sizeof(req));
@@ -387,7 +505,8 @@ bool bnxt_promisc_ok(struct bnxt_softc *softc)
 }
 
 static int
-bnxt_hwrm_set_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
+bnxt_hwrm_set_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
+    bool trusted)
 {
 	struct hwrm_func_cfg_input req = {0};
 	int rc;
@@ -399,7 +518,7 @@ bnxt_hwrm_set_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
 
 	req.fid = htole16(vf->fw_fid);
 
-	if (vf->flags & BNXT_VF_TRUST)
+	if (trusted)
 		req.flags = htole32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);
 	else
 		req.flags = htole32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_DISABLE);
@@ -426,14 +545,9 @@ bnxt_set_vf_trust(struct bnxt_softc *softc, int vf_id, bool trusted)
 	}
 	vf = &softc->pf.vf[vf_id];
 
-	if (trusted)
-		vf->flags |= BNXT_VF_TRUST;
-	else
-		vf->flags &= ~BNXT_VF_TRUST;
-
 	BNXT_SRIOV_UNLOCK(softc);
 
-	rc = bnxt_hwrm_set_trusted_vf(softc, vf);
+	rc = bnxt_hwrm_set_trusted_vf(softc, vf, trusted);
 	if (rc == 0) {
 		BNXT_SRIOV_LOCK(softc);
 		if (softc->pf.num_vfs != 0 && vf_id < softc->pf.num_vfs) {
@@ -454,6 +568,8 @@ bnxt_vf_configure_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
 	u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input);
 	struct hwrm_func_vf_cfg_input *req =
 		(struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr;
+	u8 mac[ETHER_ADDR_LEN];
+	int rc;
 
 	/* Allow VF to set a valid MAC address, if trust is set to on or
 	 * if the PF assigned MAC address is zero
@@ -465,8 +581,14 @@ bnxt_vf_configure_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
 		if (bnxt_eth_addr_valid(req->dflt_mac_addr) &&
 		    (trust || !bnxt_eth_addr_valid(vf->mac_addr) ||
 		     bnxt_eth_addr_equal(req->dflt_mac_addr, vf->mac_addr))) {
-			bnxt_eth_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr);
-			return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
+			bnxt_eth_addr_copy(mac, req->dflt_mac_addr);
+			rc = bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
+			if (rc == 0) {
+				BNXT_SRIOV_LOCK(softc);
+				bnxt_eth_addr_copy(vf->vf_mac_addr, mac);
+				BNXT_SRIOV_UNLOCK(softc);
+			}
+			return (rc);
 		}
 		return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
 	}
@@ -633,6 +755,9 @@ bnxt_hwrm_set_vf_spoofchk(struct bnxt_softc *sc, struct bnxt_vf_info *vf,
 	struct hwrm_func_cfg_input req = {0};
 	int rc = 0;
 
+	if (sc->hwrm_spec_code < 0x10701)
+		return (EOPNOTSUPP);
+
 	bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_CFG);
 
 	req.fid = htole16(vf->fw_fid);
@@ -1018,6 +1143,8 @@ void bnxt_sriov_attach(struct bnxt_softc *softc)
 	rc = pci_iov_attach(dev, pf_schema, vf_schema);
 	if (rc)
 		device_printf(dev, "Failed to initialize SR-IOV (error=%d)\n", rc);
+	else
+		softc->pf.iov_attached = true;
 }
 
 #else
diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sriov.h b/sys/dev/bnxt/bnxt_en/bnxt_sriov.h
index 8030af9e3fc1..d83b0c98e629 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sriov.h
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sriov.h
@@ -79,6 +79,7 @@ struct bnxt_vf_info {
 	struct		iflib_dma_info	hwrm_cmd_req;
 	uint16_t	trusted;
 	bool		spoofchk;
+	bool		configured;
 };
 
 struct bnxt_resc_map {
@@ -94,6 +95,8 @@ void bnxt_sriov_attach(struct bnxt_softc *softc);
 int bnxt_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params);
 void bnxt_iov_uninit(if_ctx_t ctx);
 int bnxt_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params);
+struct if_vf_status;
+int bnxt_vf_status(if_ctx_t ctx, struct if_vf_status **statusp);
 int bnxt_hwrm_func_vf_resource_free(struct bnxt_softc *softc, int num_vfs);
 void bnxt_free_vf_resources(struct bnxt_softc *softc);
 int bnxt_create_trusted_vf_sysctls(struct bnxt_softc *softc, uint16_t num_vfs);
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 776da70a6d1c..630301604e3e 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -368,6 +368,7 @@ static device_method_t bnxt_iflib_methods[] = {
 	DEVMETHOD(ifdi_iov_init, bnxt_iov_init),
 	DEVMETHOD(ifdi_iov_uninit, bnxt_iov_uninit),
 	DEVMETHOD(ifdi_iov_vf_add, bnxt_iov_vf_add),
+	DEVMETHOD(ifdi_vf_status, bnxt_vf_status),
 #endif
 	DEVMETHOD_END
 };