Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Apr 2026 06:45:00 +0000
From:      Sumit Saxena <ssaxena@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Subject:   git: fcf100da9b38 - main - bnxt_en: Add VF forwarded HWRM request handling
Message-ID:  <69f0576c.313e1.4e0d4d6b@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by ssaxena:

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

commit fcf100da9b381ad9d81f94499fdadea15ae2b431
Author:     Chandrakanth Patil <chandrakanth.patil@broadcom.com>
AuthorDate: 2026-03-31 16:59:01 +0000
Commit:     Sumit Saxena <ssaxena@FreeBSD.org>
CommitDate: 2026-04-28 06:29:37 +0000

    bnxt_en: Add VF forwarded HWRM request handling
    
    Enable the Physical Function to proxy HWRM commands issued by Virtual
    Functions through the firmware forwarded-request mechanism.
    
    When a VF issues a command that requires PF arbitration, the firmware
    delivers a CMPL_BASE_TYPE_HWRM_FWD_REQ completion to the PF async ring.
    
    * bnxt_process_async_msg() recognises CMPL_BASE_TYPE_HWRM_FWD_REQ,
      identifies the originating VF by its firmware function ID, sets the
      corresponding bit in pf.vf_event_bmap, and raises
      BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT to schedule deferred processing.
    
    * bnxt_sp_task() dispatches to bnxt_hwrm_exec_fwd_req(), which iterates
      over all pending VF bits and calls bnxt_vf_req_validate_snd() for each.
    
    * bnxt_vf_req_validate_snd() inspects the encapsulated request type:
      HWRM_FUNC_VF_CFG (MAC change) is handled by bnxt_vf_configure_mac()
      which enforces trust/existing-MAC rules; HWRM_CFA_L2_FILTER_ALLOC is
      handled by bnxt_vf_validate_set_mac(); HWRM_FUNC_CFG is forwarded
      as-is; all other commands are rejected.
    
    All forwarded-request code is guarded by #ifdef PCI_IOV.
    
    MFC after:      1 month
    Reviewed by:    ssaxena
    Differential Revision: https://reviews.freebsd.org/D56199
---
 sys/dev/bnxt/bnxt_en/bnxt_sriov.c | 178 ++++++++++++++++++++++++++++++++++++++
 sys/dev/bnxt/bnxt_en/if_bnxt.c    |  22 +++++
 2 files changed, 200 insertions(+)

diff --git a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
index 0ca1881514c2..9bec955f9890 100644
--- a/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
+++ b/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
@@ -274,6 +274,184 @@ update_vf_mac_exit:
 		bnxt_approve_mac(sc);
 }
 
+static int
+bnxt_hwrm_fwd_err_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
+		       u32 msg_size)
+{
+	struct hwrm_reject_fwd_resp_input req;
+
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_REJECT_FWD_RESP);
+
+	if (msg_size > sizeof(req.encap_request))
+		msg_size = sizeof(req.encap_request);
+
+	req.target_id = cpu_to_le16(vf->fw_fid);
+	req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
+	memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
+
+	BNXT_HWRM_LOCK(softc);
+	int rc = _hwrm_send_message(softc, &req, sizeof(req));
+	BNXT_HWRM_UNLOCK(softc);
+	if (rc)
+		device_printf(softc->dev, "hwrm_fwd_err_resp failed (error=%d)\n", rc);
+
+	return rc;
+}
+
+static int
+bnxt_hwrm_exec_fwd_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
+			u32 msg_size)
+{
+	struct hwrm_exec_fwd_resp_input req;
+
+	if (BNXT_EXEC_FWD_RESP_SIZE_ERR(msg_size))
+		return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
+
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_EXEC_FWD_RESP);
+
+	req.target_id = cpu_to_le16(vf->fw_fid);
+	req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
+	memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
+
+	BNXT_HWRM_LOCK(softc);
+	int rc = _hwrm_send_message(softc, &req, sizeof(req));
+	BNXT_HWRM_UNLOCK(softc);
+	if (rc)
+		device_printf(softc->dev, "hwrm_exec_fw_resp failed (error=%d)\n", rc);
+
+	return rc;
+}
+
+static int
+bnxt_hwrm_func_qcfg_flags(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
+{
+	struct hwrm_func_qcfg_input req;
+	struct hwrm_func_qcfg_output *resp =
+		(void *)softc->hwrm_cmd_resp.idi_vaddr;
+
+	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
+
+	req.fid = cpu_to_le16(BNXT_PF(softc) ? vf->fw_fid : 0xffff);
+
+	BNXT_HWRM_LOCK(softc);
+	int rc = _hwrm_send_message(softc, &req, sizeof(req));
+	BNXT_HWRM_UNLOCK(softc);
+	if (!rc)
+		vf->func_qcfg_flags = cpu_to_le16(resp->flags);
+
+	return rc;
+}
+
+bool
+bnxt_is_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
+{
+	bnxt_hwrm_func_qcfg_flags(softc, vf);
+	return !!(vf->func_qcfg_flags & HWRM_FUNC_QCFG_OUTPUT_FLAGS_TRUSTED_VF);
+}
+
+static int
+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;
+
+	/* Allow VF to set a valid MAC address, if trust is set to on or
+	 * if the PF assigned MAC address is zero
+	 */
+	if (req->enables &
+	    cpu_to_le32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR)) {
+		bool trust = bnxt_is_trusted_vf(softc, vf);
+
+		if (is_valid_ether_addr(req->dflt_mac_addr) &&
+		    (trust || !is_valid_ether_addr(vf->mac_addr) ||
+		     ether_addr_equal(req->dflt_mac_addr, vf->mac_addr))) {
+			ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr);
+			return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
+		}
+		return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
+	}
+	return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
+}
+
+static int bnxt_vf_validate_set_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
+{
+	u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);
+	struct hwrm_cfa_l2_filter_alloc_input *req =
+		(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;
+	bool mac_ok = false;
+
+	if (!is_valid_ether_addr((const u8 *)req->l2_addr))
+		return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
+
+	/* Allow VF to set a valid MAC address, if trust is set to on.
+	 * Or VF MAC address must first match MAC address in PF's context.
+	 * Otherwise, it must match the VF MAC address if firmware spec >=
+	 * 1.2.2
+	 */
+	if (bnxt_is_trusted_vf(softc, vf)) {
+		mac_ok = true;
+	} else if (is_valid_ether_addr(vf->mac_addr)) {
+		if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
+			mac_ok = true;
+	} else if (is_valid_ether_addr(vf->vf_mac_addr)) {
+		if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr))
+			mac_ok = true;
+	} else {
+		mac_ok = true;
+	}
+	if (mac_ok)
+		return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
+
+	return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
+}
+
+static int bnxt_vf_req_validate_snd(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
+{
+	int rc = 0;
+	struct input *encap_req = vf->hwrm_cmd_req_addr;
+	u32 req_type = le16_to_cpu(encap_req->req_type);
+
+	switch (req_type) {
+	case HWRM_FUNC_VF_CFG:
+		rc = bnxt_vf_configure_mac(softc, vf);
+		break;
+	case HWRM_CFA_L2_FILTER_ALLOC:
+		rc = bnxt_vf_validate_set_mac(softc, vf);
+		break;
+	case HWRM_FUNC_CFG:
+		rc = bnxt_hwrm_exec_fwd_resp(
+			softc, vf, sizeof(struct hwrm_func_cfg_input));
+		break;
+	case HWRM_PORT_PHY_QCFG:
+		/* ckp todo: Disable set VF link command now, enable it later
+		 * Auto neg works as of now.
+		 * rc = bnxt_vf_set_link(softc, vf);
+		 */
+		break;
+	default:
+		rc = bnxt_hwrm_fwd_err_resp(softc, vf, softc->hwrm_max_req_len);
+		break;
+	}
+	return rc;
+}
+
+void bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc)
+{
+	u32 i = 0, active_vfs = softc->pf.active_vfs, vf_id;
+
+	/* Scan through VF's and process commands */
+	while (1) {
+		vf_id = find_next_bit(softc->pf.vf_event_bmap, active_vfs, i);
+		if (vf_id >= active_vfs)
+			break;
+
+		clear_bit(vf_id, softc->pf.vf_event_bmap);
+		bnxt_vf_req_validate_snd(softc, &softc->pf.vf[vf_id]);
+		i = vf_id + 1;
+	}
+}
+
 static int
 bnxt_hwrm_func_vf_resc_cfg(struct bnxt_softc *softc, int num_vfs, bool reset)
 {
diff --git a/sys/dev/bnxt/bnxt_en/if_bnxt.c b/sys/dev/bnxt/bnxt_en/if_bnxt.c
index 9226ea85a34a..83cace50291f 100644
--- a/sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ b/sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -2411,6 +2411,11 @@ static void bnxt_sp_task(struct work_struct *work)
 		return;
 	}
 
+#ifdef PCI_IOV
+	if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event))
+		bnxt_hwrm_exec_fwd_req(bp);
+#endif
+
 	if (test_and_clear_bit(BNXT_FW_RESET_NOTIFY_SP_EVENT, &bp->sp_event)) {
 		if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state) ||
 		    test_bit(BNXT_STATE_FW_NON_FATAL_COND, &bp->state))
@@ -3868,6 +3873,10 @@ bnxt_process_async_msg(struct bnxt_cp_ring *cpr, tx_cmpl_t *cmpl)
 {
 	struct bnxt_softc *softc = cpr->ring.softc;
 	uint16_t type = cmpl->flags_type & TX_CMPL_TYPE_MASK;
+#ifdef PCI_IOV
+	struct hwrm_fwd_req_cmpl *fwd_req_cmpl = (struct hwrm_fwd_req_cmpl *)cmpl;
+	uint16_t vf_id;
+#endif
 
 	switch (type) {
 	case HWRM_CMPL_TYPE_HWRM_DONE:
@@ -3876,6 +3885,19 @@ bnxt_process_async_msg(struct bnxt_cp_ring *cpr, tx_cmpl_t *cmpl)
 	case HWRM_ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT:
 		bnxt_handle_async_event(softc, (cmpl_base_t *) cmpl);
 		break;
+#ifdef PCI_IOV
+	case CMPL_BASE_TYPE_HWRM_FWD_REQ:
+		vf_id = le16_to_cpu(fwd_req_cmpl->source_id);
+
+		if ((vf_id < softc->pf.first_vf_id) ||
+		    (vf_id >= softc->pf.first_vf_id + softc->pf.active_vfs))
+			return;
+
+		set_bit(vf_id - softc->pf.first_vf_id, softc->pf.vf_event_bmap);
+		set_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &softc->sp_event);
+		bnxt_queue_sp_work(softc);
+		break;
+#endif
 	default:
 		device_printf(softc->dev, "%s:%d Unhandled async message %x\n",
 				__FUNCTION__, __LINE__, type);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f0576c.313e1.4e0d4d6b>