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>
