Path: blob/main/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
283101 views
#include <linux/delay.h>1#include <linux/etherdevice.h>23#include "opt_global.h"4#include "bnxt.h"5#include "hsi_struct_def.h"6#include "bnxt_hwrm.h"7#include "bnxt_sriov.h"89#ifdef PCI_IOV1011static int12bnxt_set_vf_admin_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf,13const uint8_t *mac)14{15struct hwrm_func_cfg_input req = {0};16int rc;1718if (!BNXT_PF(softc))19return (EOPNOTSUPP);2021bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);2223req.fid = htole16(vf->fw_fid);24req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);25memcpy(req.dflt_mac_addr, mac, ETHER_ADDR_LEN);2627BNXT_HWRM_LOCK(softc);28rc = _hwrm_send_message(softc, &req, sizeof(req));29BNXT_HWRM_UNLOCK(softc);3031return (rc);32}3334static bool35bnxt_vf_parse_schema(struct bnxt_softc *softc, struct bnxt_vf_info *vf,36const nvlist_t *params)37{38const void *mac;39size_t maclen;4041memset(vf->mac_addr, 0, ETHER_ADDR_LEN);42memset(vf->vf_mac_addr, 0, ETHER_ADDR_LEN);4344if (params == NULL)45return (false);4647if (nvlist_exists(params, "mac-anti-spoof"))48vf->spoofchk = nvlist_get_bool(params, "mac-anti-spoof");49if (nvlist_exists(params, "trust"))50vf->trusted = nvlist_get_bool(params, "trust");5152if (!nvlist_exists(params, "mac-addr"))53return (false);5455mac = nvlist_get_binary(params, "mac-addr", &maclen);5657if (maclen != ETHER_ADDR_LEN)58return (false);5960if (!is_valid_ether_addr(mac))61return (false);6263memcpy(vf->mac_addr, mac, ETHER_ADDR_LEN);64return (true);65}6667/* Add a Virtual Functions */68int69bnxt_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)70{71struct bnxt_softc *softc = iflib_get_softc(ctx);72struct bnxt_vf_info *vf = &softc->pf.vf[vfnum];73int rc;7475vf->fw_fid = softc->pf.first_vf_id + vfnum;76vf->vfnum = vfnum;7778/*79* If the schema provided a valid admin MAC, program it into firmware.80*/81if (bnxt_vf_parse_schema(softc, vf, params)) {82rc = bnxt_set_vf_admin_mac(softc, vf, vf->mac_addr);83if (rc)84device_printf(softc->dev,85"vf%u: PF-assigned MAC programming failed (rc=%d), falling back to firmware/default MAC\n",86vfnum, rc);87}8889(void)bnxt_set_vf_trust(softc, vfnum, vf->trusted);90(void)bnxt_set_vf_spoofchk(softc, vfnum, vf->spoofchk);9192return 0;93}9495/* Free driver-side VF resources (called after hwrm_vf_resc_free) */96void bnxt_free_vf_resources(struct bnxt_softc *softc)97{98int i;99size_t page_size = 1UL << softc->pf.vf_hwrm_cmd_req_page_shift;100101softc->pf.active_vfs = 0;102103if (softc->pf.vf) {104kfree(softc->pf.vf);105softc->pf.vf = NULL;106}107if (softc->pf.vf_event_bmap) {108kfree(softc->pf.vf_event_bmap);109softc->pf.vf_event_bmap = NULL;110}111for (i = 0; i < softc->pf.hwrm_cmd_req_pages; i++) {112if (softc->pf.hwrm_cmd_req_addr[i]) {113dma_free_coherent(&softc->pdev->dev, page_size,114softc->pf.hwrm_cmd_req_addr[i],115softc->pf.hwrm_cmd_req_dma_addr[i]);116softc->pf.hwrm_cmd_req_addr[i] = NULL;117}118}119}120121/* Free firmware-side VF resources */122int123bnxt_hwrm_func_vf_resource_free(struct bnxt_softc *softc, int num_vfs)124{125int i, rc;126int first_vf_id, last_vf_id;127struct hwrm_func_vf_resc_free_input req;128129bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_RESC_FREE);130131first_vf_id = softc->pf.first_vf_id;132last_vf_id = first_vf_id + num_vfs - 1;133134BNXT_HWRM_LOCK(softc);135for (i = first_vf_id; i <= last_vf_id; i++) {136req.vf_id = cpu_to_le16(i);137rc = _hwrm_send_message(softc, &req, sizeof(req));138if (rc)139break;140}141BNXT_HWRM_UNLOCK(softc);142143return rc;144}145146/* Free all VF resources */147void bnxt_iov_uninit(if_ctx_t ctx)148{149int rc;150struct bnxt_softc *softc = iflib_get_softc(ctx);151int num_vfs = softc->pf.num_vfs;152153if (!num_vfs)154return;155156BNXT_SRIOV_LOCK(softc);157softc->pf.num_vfs = 0;158BNXT_SRIOV_UNLOCK(softc);159160rc = bnxt_hwrm_func_vf_resource_free(softc, num_vfs);161if (rc)162device_printf(softc->dev, "VF resource free HWRM failed: %d\n", rc);163164bnxt_destroy_trusted_vf_sysctls(softc);165bnxt_free_vf_resources(softc);166BNXT_SRIOV_LOCK_DESTROY(softc);167}168169static inline int170bnxt_set_vf_resc_field(uint16_t *min_field, uint16_t *max_field,171uint16_t hw_max, uint16_t pf_alloc, int num_vfs)172{173uint16_t val = 0;174175if (num_vfs <= 0)176return -EINVAL;177178if (hw_max > pf_alloc)179val = (hw_max - pf_alloc) / num_vfs;180181*min_field = *max_field = cpu_to_le16(val);182183return 0;184}185186static int bnxt_set_vf_params(struct bnxt_softc *softc, int vf_id)187{188struct hwrm_func_cfg_input req = {0};189struct bnxt_vf_info *vf;190int rc;191192bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);193194vf = &softc->pf.vf[vf_id];195req.fid = cpu_to_le16(vf->fw_fid);196197198if (is_valid_ether_addr(vf->mac_addr)) {199req.enables |= cpu_to_le32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);200memcpy(req.dflt_mac_addr, vf->mac_addr, ETHER_ADDR_LEN);201}202203if (vf->vlan) {204req.enables |= cpu_to_le32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_VLAN);205req.dflt_vlan = cpu_to_le16(vf->vlan);206}207208if (vf->flags & BNXT_VF_TRUST)209req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);210211BNXT_HWRM_LOCK(softc);212rc = _hwrm_send_message(softc, &req, sizeof(req));213BNXT_HWRM_UNLOCK(softc);214if (rc)215device_printf(softc->dev, "hwrm_func_cfg failed (error:%d)\n", rc);216217return rc;218}219220int bnxt_approve_mac(struct bnxt_softc *sc)221{222223struct hwrm_func_vf_cfg_input req = (struct hwrm_func_vf_cfg_input){0};224struct bnxt_vf_info *vf = &sc->vf;225u8 *mac = vf->mac_addr;226int rc = 0;227228if (!BNXT_VF(sc))229return EOPNOTSUPP;230231bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_VF_CFG);232req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);233memcpy(req.dflt_mac_addr, mac, ETHER_ADDR_LEN);234235BNXT_HWRM_LOCK(sc);236rc = _hwrm_send_message(sc, &req, sizeof(req));237BNXT_HWRM_UNLOCK(sc);238239if (rc) {240device_printf(sc->dev,241"VF MAC %02x:%02x:%02x:%02x:%02x:%02x not approved by PF (rc=%d)\n",242mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], rc);243return EADDRNOTAVAIL;244}245return rc;246}247248void249bnxt_update_vf_mac(struct bnxt_softc *sc)250{251int rc = 0;252struct hwrm_func_qcaps_input req = {0};253struct hwrm_func_qcaps_output *resp =254(void *)sc->hwrm_cmd_resp.idi_vaddr;255bool inform_pf = false;256257bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_QCAPS);258req.fid = htole16(0xffff);259260BNXT_HWRM_LOCK(sc);261rc = _hwrm_send_message(sc, &req, sizeof(req));262if (rc)263goto update_vf_mac_exit;264265if (!ether_addr_equal(resp->mac_address, sc->vf.mac_addr)) {266memcpy(sc->vf.mac_addr, resp->mac_address, ETHER_ADDR_LEN);267if (!is_valid_ether_addr(sc->vf.mac_addr))268inform_pf = true;269}270271if (is_valid_ether_addr(sc->vf.mac_addr)) {272iflib_set_mac(sc->ctx, sc->vf.mac_addr);273memcpy(sc->func.mac_addr, sc->vf.mac_addr, ETHER_ADDR_LEN);274}275276update_vf_mac_exit:277BNXT_HWRM_UNLOCK(sc);278if (inform_pf)279bnxt_approve_mac(sc);280}281282static int283bnxt_hwrm_fwd_err_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,284u32 msg_size)285{286struct hwrm_reject_fwd_resp_input req;287288bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_REJECT_FWD_RESP);289290if (msg_size > sizeof(req.encap_request))291msg_size = sizeof(req.encap_request);292293req.target_id = cpu_to_le16(vf->fw_fid);294req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);295memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);296297BNXT_HWRM_LOCK(softc);298int rc = _hwrm_send_message(softc, &req, sizeof(req));299BNXT_HWRM_UNLOCK(softc);300if (rc)301device_printf(softc->dev, "hwrm_fwd_err_resp failed (error=%d)\n", rc);302303return rc;304}305306static int307bnxt_hwrm_exec_fwd_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,308u32 msg_size)309{310struct hwrm_exec_fwd_resp_input req;311312if (BNXT_EXEC_FWD_RESP_SIZE_ERR(msg_size))313return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);314315bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_EXEC_FWD_RESP);316317req.target_id = cpu_to_le16(vf->fw_fid);318req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);319memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);320321BNXT_HWRM_LOCK(softc);322int rc = _hwrm_send_message(softc, &req, sizeof(req));323BNXT_HWRM_UNLOCK(softc);324if (rc)325device_printf(softc->dev, "hwrm_exec_fw_resp failed (error=%d)\n", rc);326327return rc;328}329330static int331bnxt_hwrm_func_qcfg_flags(struct bnxt_softc *softc, struct bnxt_vf_info *vf)332{333struct hwrm_func_qcfg_input req;334struct hwrm_func_qcfg_output *resp =335(void *)softc->hwrm_cmd_resp.idi_vaddr;336337bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);338339req.fid = cpu_to_le16(BNXT_PF(softc) ? vf->fw_fid : 0xffff);340341BNXT_HWRM_LOCK(softc);342int rc = _hwrm_send_message(softc, &req, sizeof(req));343BNXT_HWRM_UNLOCK(softc);344if (!rc)345vf->func_qcfg_flags = cpu_to_le16(resp->flags);346347return rc;348}349350bool351bnxt_is_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)352{353bnxt_hwrm_func_qcfg_flags(softc, vf);354return !!(vf->func_qcfg_flags & HWRM_FUNC_QCFG_OUTPUT_FLAGS_TRUSTED_VF);355}356357bool bnxt_promisc_ok(struct bnxt_softc *softc)358{359if (BNXT_VF(softc) && !bnxt_is_trusted_vf(softc, &softc->vf))360return false;361return true;362}363364static int365bnxt_hwrm_set_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)366{367struct hwrm_func_cfg_input req = {0};368int rc;369370if (!(softc->fw_cap & BNXT_FW_CAP_TRUSTED_VF))371return (EOPNOTSUPP);372373bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);374375req.fid = htole16(vf->fw_fid);376377if (vf->flags & BNXT_VF_TRUST)378req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);379else380req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_DISABLE);381382BNXT_HWRM_LOCK(softc);383rc = _hwrm_send_message(softc, &req, sizeof(req));384BNXT_HWRM_UNLOCK(softc);385if (rc)386device_printf(softc->dev, "bnxt_hwrm_set_trusted_vf failed. rc:%d\n", rc);387388return rc;389}390391int392bnxt_set_vf_trust(struct bnxt_softc *softc, int vf_id, bool trusted)393{394int rc;395struct bnxt_vf_info *vf = NULL;396397BNXT_SRIOV_LOCK(softc);398if (softc->pf.num_vfs == 0 || vf_id >= softc->pf.num_vfs) {399BNXT_SRIOV_UNLOCK(softc);400return (ENOENT);401}402vf = &softc->pf.vf[vf_id];403404if (trusted)405vf->flags |= BNXT_VF_TRUST;406else407vf->flags &= ~BNXT_VF_TRUST;408409BNXT_SRIOV_UNLOCK(softc);410411rc = bnxt_hwrm_set_trusted_vf(softc, vf);412if (rc == 0) {413BNXT_SRIOV_LOCK(softc);414if (softc->pf.num_vfs != 0 && vf_id < softc->pf.num_vfs) {415vf = &softc->pf.vf[vf_id];416if (trusted)417vf->flags |= BNXT_VF_TRUST;418else419vf->flags &= ~BNXT_VF_TRUST;420}421BNXT_SRIOV_UNLOCK(softc);422}423return rc;424}425426static int427bnxt_vf_configure_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)428{429u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input);430struct hwrm_func_vf_cfg_input *req =431(struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr;432433/* Allow VF to set a valid MAC address, if trust is set to on or434* if the PF assigned MAC address is zero435*/436if (req->enables &437cpu_to_le32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR)) {438bool trust = bnxt_is_trusted_vf(softc, vf);439440if (is_valid_ether_addr(req->dflt_mac_addr) &&441(trust || !is_valid_ether_addr(vf->mac_addr) ||442ether_addr_equal(req->dflt_mac_addr, vf->mac_addr))) {443ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr);444return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);445}446return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);447}448return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);449}450451static int bnxt_vf_validate_set_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)452{453u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);454struct hwrm_cfa_l2_filter_alloc_input *req =455(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;456bool mac_ok = false;457458if (!is_valid_ether_addr((const u8 *)req->l2_addr))459return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);460461/* Allow VF to set a valid MAC address, if trust is set to on.462* Or VF MAC address must first match MAC address in PF's context.463* Otherwise, it must match the VF MAC address if firmware spec >=464* 1.2.2465*/466if (bnxt_is_trusted_vf(softc, vf)) {467mac_ok = true;468} else if (is_valid_ether_addr(vf->mac_addr)) {469if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))470mac_ok = true;471} else if (is_valid_ether_addr(vf->vf_mac_addr)) {472if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr))473mac_ok = true;474} else {475mac_ok = true;476}477if (mac_ok)478return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);479480return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);481}482483static int bnxt_vf_req_validate_snd(struct bnxt_softc *softc, struct bnxt_vf_info *vf)484{485int rc = 0;486struct input *encap_req = vf->hwrm_cmd_req_addr;487u32 req_type = le16_to_cpu(encap_req->req_type);488489switch (req_type) {490case HWRM_FUNC_VF_CFG:491rc = bnxt_vf_configure_mac(softc, vf);492break;493case HWRM_CFA_L2_FILTER_ALLOC:494rc = bnxt_vf_validate_set_mac(softc, vf);495break;496case HWRM_FUNC_CFG:497rc = bnxt_hwrm_exec_fwd_resp(498softc, vf, sizeof(struct hwrm_func_cfg_input));499break;500case HWRM_PORT_PHY_QCFG:501/* ckp todo: Disable set VF link command now, enable it later502* Auto neg works as of now.503* rc = bnxt_vf_set_link(softc, vf);504*/505break;506default:507rc = bnxt_hwrm_fwd_err_resp(softc, vf, softc->hwrm_max_req_len);508break;509}510return rc;511}512513void bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc)514{515u32 i = 0, active_vfs = softc->pf.active_vfs, vf_id;516517/* Scan through VF's and process commands */518while (1) {519vf_id = find_next_bit(softc->pf.vf_event_bmap, active_vfs, i);520if (vf_id >= active_vfs)521break;522523clear_bit(vf_id, softc->pf.vf_event_bmap);524bnxt_vf_req_validate_snd(softc, &softc->pf.vf[vf_id]);525i = vf_id + 1;526}527}528529/* destroy VF sysctls when VFs are removed / PF detaches. */530void531bnxt_destroy_trusted_vf_sysctls(struct bnxt_softc *softc)532{533sysctl_ctx_free(&softc->pf.sysctl_ctx);534}535536/* Handler for: dev.bnxt.<unit>.vf<N>.trusted (0/1) */537static int538bnxt_sysctl_vf_trusted(SYSCTL_HANDLER_ARGS)539{540struct bnxt_softc *softc = (struct bnxt_softc *)arg1;541int vf_id = (int)arg2;542int val, rc;543544BNXT_SRIOV_LOCK(softc);545if (softc->pf.num_vfs == 0 || vf_id < 0 || vf_id >= softc->pf.num_vfs) {546BNXT_SRIOV_UNLOCK(softc);547return (ENOENT);548}549val = (softc->pf.vf[vf_id].flags & BNXT_VF_TRUST) ? 1 : 0;550BNXT_SRIOV_UNLOCK(softc);551552rc = sysctl_handle_int(oidp, &val, 0, req);553if (rc)554return rc;555556/* If no new value supplied, it was a READ */557if (req->newptr == NULL)558return 0;559560/* WRITE path: 'val' now holds the user's 0/1 */561rc = bnxt_set_vf_trust(softc, vf_id, (val != 0));562563return rc;564}565566/*567* Create per-VF sysctls:568* dev.bnxt.<unit>.vf0.trusted569* dev.bnxt.<unit>.vf1.trusted570* ..571*/572int573bnxt_create_trusted_vf_sysctls(struct bnxt_softc *softc, uint16_t num_vfs)574{575struct sysctl_oid_list *root_list;576struct sysctl_oid *vf_node;577char node_name[16];578579/* use the device's sysctl tree as root: dev.bnxt.<unit>. */580sysctl_ctx_init(&softc->pf.sysctl_ctx);581root_list = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));582583for (int i = 0; i < num_vfs; i++) {584snprintf(node_name, sizeof(node_name), "vf%d", i);585586/* dev.bnxt.<unit>.vfN */587vf_node = SYSCTL_ADD_NODE(&softc->pf.sysctl_ctx,588root_list, OID_AUTO,589node_name, CTLFLAG_RW, 0, "VF node");590591/* dev.bnxt.<unit>.vfN.trusted */592SYSCTL_ADD_PROC(&softc->pf.sysctl_ctx,593SYSCTL_CHILDREN(vf_node),594OID_AUTO, "trusted",595CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,596softc, i, bnxt_sysctl_vf_trusted, "I",597"0=untrusted (default), 1=trusted");598}599return 0;600}601602static int603bnxt_hwrm_set_vf_spoofchk(struct bnxt_softc *sc, struct bnxt_vf_info *vf,604bool enable)605{606struct hwrm_func_cfg_input req = {0};607int rc = 0;608609bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_CFG);610611req.fid = htole16(vf->fw_fid);612req.flags = htole32(enable ?613HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE :614HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE);615616BNXT_HWRM_LOCK(sc);617rc = _hwrm_send_message(sc, &req, sizeof(req));618BNXT_HWRM_UNLOCK(sc);619if (rc)620device_printf(sc->dev, "bnxt_hwrm_set_vf_spoofchk failed. rc:%d\n", rc);621622return rc;623}624625int626bnxt_set_vf_spoofchk(struct bnxt_softc *sc, int vf_id, bool enable)627{628struct bnxt_vf_info *vf;629int rc;630631BNXT_SRIOV_LOCK(sc);632if (sc->pf.num_vfs == 0 || vf_id >= sc->pf.num_vfs) {633BNXT_SRIOV_UNLOCK(sc);634return (ENOENT);635}636vf = &sc->pf.vf[vf_id];637BNXT_SRIOV_UNLOCK(sc);638639rc = bnxt_hwrm_set_vf_spoofchk(sc, vf, enable);640if (rc == 0) {641BNXT_SRIOV_LOCK(sc);642if (sc->pf.num_vfs != 0 && vf_id < sc->pf.num_vfs) {643vf = &sc->pf.vf[vf_id];644if (enable)645vf->flags |= BNXT_VF_SPOOFCHK;646else647vf->flags &= ~BNXT_VF_SPOOFCHK;648}649BNXT_SRIOV_UNLOCK(sc);650}651return rc;652}653654static int655bnxt_sysctl_vf_spoofchk(SYSCTL_HANDLER_ARGS)656{657struct bnxt_softc *sc = (struct bnxt_softc *)arg1;658int vf_id = (int)arg2;659int val, rc;660661BNXT_SRIOV_LOCK(sc);662if (sc->pf.num_vfs == 0 || vf_id >= sc->pf.num_vfs) {663BNXT_SRIOV_UNLOCK(sc);664return (ENOENT);665}666val = (sc->pf.vf[vf_id].flags & BNXT_VF_SPOOFCHK) ? 1 : 0;667BNXT_SRIOV_UNLOCK(sc);668669rc = sysctl_handle_int(oidp, &val, 0, req);670if (rc || req->newptr == NULL)671return rc;672673return bnxt_set_vf_spoofchk(sc, vf_id, val != 0);674}675676/*677* Create per-VF spoofchk:678* dev.bnxt.<unit>.vf0.spoofchk679* dev.bnxt.<unit>.vf1.spoofchk680* ..681*/682int683bnxt_create_spoofchk_vf_sysctls(struct bnxt_softc *softc, uint16_t num_vfs)684{685struct sysctl_oid_list *root_list;686struct sysctl_oid *vf_node;687char node_name[16];688689/* Reuse the same ctx & root tree as trusted vf */690root_list = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));691692for (int i = 0; i < num_vfs; i++) {693snprintf(node_name, sizeof(node_name), "vf%d", i);694695vf_node = SYSCTL_ADD_NODE(&softc->pf.sysctl_ctx,696root_list, OID_AUTO,697node_name, CTLFLAG_RW, 0, "VF node");698699SYSCTL_ADD_PROC(&softc->pf.sysctl_ctx,700SYSCTL_CHILDREN(vf_node),701OID_AUTO, "spoofchk",702CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,703softc, i, bnxt_sysctl_vf_spoofchk, "I",704"0=spoofchk off, 1=spoofchk on");705}706return 0;707}708709static int710bnxt_hwrm_func_vf_resc_cfg(struct bnxt_softc *softc, int num_vfs, bool reset)711{712struct hwrm_func_vf_resource_cfg_input req = {0};713struct bnxt_pf_info *pf = &softc->pf;714struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg;715struct bnxt_hw_resc *hw_resc = &softc->hw_resc;716int i, rc;717uint16_t msix_val = 0;718719bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_RESOURCE_CFG);720struct bnxt_resc_map resc_table[] = {721{ &req.min_tx_rings, &req.max_tx_rings, hw_resc->max_tx_rings, fn_qcfg->alloc_tx_rings },722{ &req.min_rx_rings, &req.max_rx_rings, hw_resc->max_rx_rings, fn_qcfg->alloc_rx_rings },723{ &req.min_cmpl_rings, &req.max_cmpl_rings, hw_resc->max_cp_rings, fn_qcfg->alloc_completion_rings },724{ &req.min_stat_ctx, &req.max_stat_ctx, hw_resc->max_stat_ctxs, fn_qcfg->alloc_stat_ctx },725{ &req.min_vnics, &req.max_vnics, hw_resc->max_vnics, fn_qcfg->alloc_vnics },726{ &req.min_hw_ring_grps, &req.max_hw_ring_grps, hw_resc->max_hw_ring_grps, fn_qcfg->alloc_hw_ring_grps },727{ &req.min_rsscos_ctx, &req.max_rsscos_ctx, hw_resc->max_rsscos_ctxs, fn_qcfg->alloc_rss_ctx },728{ &req.min_l2_ctxs, &req.max_l2_ctxs, hw_resc->max_l2_ctxs, fn_qcfg->alloc_l2_ctx },729};730731for (i = 0; i < sizeof(resc_table) / sizeof(resc_table[0]); i++) {732rc = bnxt_set_vf_resc_field(resc_table[i].min_field,733resc_table[i].max_field,734resc_table[i].hw_max,735resc_table[i].pf_alloc,736num_vfs);737if (rc)738return rc;739}740741if (hw_resc->max_irqs > fn_qcfg->alloc_msix && num_vfs > 0)742msix_val = (hw_resc->max_irqs - fn_qcfg->alloc_msix) / num_vfs;743744req.max_msix = cpu_to_le16(msix_val);745746for (i = 0; i < num_vfs; i++) {747struct bnxt_vf_info *vf = &pf->vf[i];748749vf->fw_fid = pf->first_vf_id + i;750if (reset) {751rc = bnxt_set_vf_params(softc, i);752if (rc)753break;754}755756req.vf_id = cpu_to_le16(vf->fw_fid);757758BNXT_HWRM_LOCK(softc);759rc = _hwrm_send_message(softc, &req, sizeof(req));760BNXT_HWRM_UNLOCK(softc);761762if (rc) {763device_printf(softc->dev, "HWRM_FUNC_VF_RESOURCE_CFG req dump:\n");764break;765}766767pf->active_vfs = i + 1;768769vf->min_tx_rings = le16_to_cpu(req.min_tx_rings);770vf->min_rx_rings = le16_to_cpu(req.min_rx_rings);771vf->min_cp_rings = le16_to_cpu(req.min_cmpl_rings);772vf->min_stat_ctxs = le16_to_cpu(req.min_stat_ctx);773vf->min_ring_grps = le16_to_cpu(req.min_hw_ring_grps);774vf->min_vnics = le16_to_cpu(req.min_vnics);775}776777if (pf->active_vfs)778memcpy(&softc->vf_resc_cfg_input, &req,779sizeof(struct hwrm_func_vf_resource_cfg_input));780781return rc;782}783784static int785bnxt_hwrm_func_buf_rgtr(struct bnxt_softc *softc)786{787int rc;788struct hwrm_func_buf_rgtr_input req;789790bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_BUF_RGTR);791792req.req_buf_num_pages = cpu_to_le16(softc->pf.hwrm_cmd_req_pages);793req.req_buf_page_size = cpu_to_le16(softc->pf.vf_hwrm_cmd_req_page_shift);794req.req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE);795req.req_buf_page_addr0 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[0]);796req.req_buf_page_addr1 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[1]);797req.req_buf_page_addr2 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[2]);798req.req_buf_page_addr3 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[3]);799800BNXT_HWRM_LOCK(softc);801rc = _hwrm_send_message(softc, &req, sizeof(req));802BNXT_HWRM_UNLOCK(softc);803804return rc;805}806807static void808bnxt_set_vf_attr(struct bnxt_softc *softc, int num_vfs)809{810int i;811struct bnxt_vf_info *vf;812813for (i = 0; i < num_vfs; i++) {814vf = &softc->pf.vf[i];815memset(vf, 0, sizeof(*vf));816}817}818819static int820bnxt_alloc_vf_resources(struct bnxt_softc *softc, int num_vfs)821{822struct pci_dev *pdev = softc->pdev;823u32 nr_pages, size, i, j, k = 0;824u32 page_size, reqs_per_page;825void *p;826827p = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL);828if (!p)829return ENOMEM;830831rcu_assign_pointer(softc->pf.vf, p);832bnxt_set_vf_attr(softc, num_vfs);833834size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE;835page_size = BNXT_PAGE_SIZE;836softc->pf.vf_hwrm_cmd_req_page_shift = BNXT_PAGE_SHIFT;837while (size > page_size * BNXT_MAX_VF_CMD_FWD_PAGES) {838page_size *= 2;839softc->pf.vf_hwrm_cmd_req_page_shift++;840}841nr_pages = DIV_ROUND_UP(size, page_size);842reqs_per_page = page_size / BNXT_HWRM_REQ_MAX_SIZE;843844for (i = 0; i < nr_pages; i++) {845softc->pf.hwrm_cmd_req_addr[i] =846dma_alloc_coherent(&pdev->dev, page_size,847&softc->pf.hwrm_cmd_req_dma_addr[i],848GFP_ATOMIC);849850if (!softc->pf.hwrm_cmd_req_addr[i])851return ENOMEM;852853for (j = 0; j < reqs_per_page && k < num_vfs; j++) {854struct bnxt_vf_info *vf = &softc->pf.vf[k];855856vf->hwrm_cmd_req_addr = (char *)softc->pf.hwrm_cmd_req_addr[i] +857j * BNXT_HWRM_REQ_MAX_SIZE;858vf->hwrm_cmd_req_dma_addr =859softc->pf.hwrm_cmd_req_dma_addr[i] + j *860BNXT_HWRM_REQ_MAX_SIZE;861k++;862}863}864865softc->pf.vf_event_bmap = kzalloc(ALIGN(DIV_ROUND_UP(num_vfs, 8),866sizeof(long)), GFP_ATOMIC);867if (!softc->pf.vf_event_bmap)868return ENOMEM;869870softc->pf.hwrm_cmd_req_pages = nr_pages;871872return 0;873}874875int bnxt_cfg_hw_sriov(struct bnxt_softc *softc, uint16_t *num_vfs, bool reset)876{877int rc;878879rc = bnxt_hwrm_func_buf_rgtr(softc);880if (rc) {881device_printf(softc->dev, "hwrm func buf rgtr failed (error=%d)\n", rc);882return (EIO);883}884885rc = bnxt_hwrm_func_vf_resc_cfg(softc, *num_vfs, reset);886if (rc) {887device_printf(softc->dev, "hwrm func VF resc config failed (error=%d)\n", rc);888return (EIO);889}890891return (0);892}893894int895bnxt_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)896{897int rc;898if_t ifp = iflib_get_ifp(ctx);899struct bnxt_softc *softc = iflib_get_softc(ctx);900bool admin_up = !!(if_getflags(ifp) & IFF_UP);901bool running = !!(if_getdrvflags(ifp) & IFF_DRV_RUNNING);902903if (!admin_up || !running) {904device_printf(softc->dev, "PF is down, rejecting VF creation\n");905return ENETDOWN;906}907908if (num_vfs > BNXT_MAX_VFS) {909device_printf(softc->dev, "Requested %u VFs exceeds maximum supported (%u)\n",910num_vfs, BNXT_MAX_VFS);911return ERANGE;912}913914/*915* Initialize SR-IOV lock before creating any SR-IOV state, so sysctl/VF916* paths can safely synchronize and error paths can always destroy it.917*/918BNXT_SRIOV_LOCK_INIT(softc, device_get_nameunit(softc->dev));919920rc = bnxt_alloc_vf_resources(softc, num_vfs);921if (rc) {922device_printf(softc->dev, "VF resource alloc failed (error=%d)\n", rc);923goto fail_lock;924}925926rc = bnxt_cfg_hw_sriov(softc, &num_vfs, false);927if (rc)928goto fail_free_vf_resc;929930rc = bnxt_create_trusted_vf_sysctls(softc, num_vfs);931if (rc) {932device_printf(softc->dev, "trusted VF sysctl creation failed (error=%d)\n", rc);933goto fail_free_hwrm_vf_resc;934}935936rc = bnxt_create_spoofchk_vf_sysctls(softc, num_vfs);937if (rc) {938device_printf(softc->dev, "spoof check VF sysctl creation failed (error=%d)\n", rc);939goto fail_free_hwrm_vf_resc;940}941942BNXT_SRIOV_LOCK(softc);943softc->pf.num_vfs = num_vfs;944BNXT_SRIOV_UNLOCK(softc);945946return 0;947948fail_free_hwrm_vf_resc:949bnxt_hwrm_func_vf_resource_free(softc, num_vfs);950fail_free_vf_resc:951bnxt_free_vf_resources(softc);952fail_lock:953BNXT_SRIOV_LOCK_DESTROY(softc);954return rc;955}956957void bnxt_sriov_attach(struct bnxt_softc *softc)958{959int rc;960device_t dev = softc->dev;961nvlist_t *pf_schema, *vf_schema;962963pf_schema = pci_iov_schema_alloc_node();964vf_schema = pci_iov_schema_alloc_node();965966/* Optionally add VF-specific attributes to the VF schema */967pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);968pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", IOV_SCHEMA_HASDEFAULT, FALSE);969pci_iov_schema_add_bool(vf_schema, "trust", IOV_SCHEMA_HASDEFAULT, FALSE);970971/* Attach SR-IOV schemas to the device */972rc = pci_iov_attach(dev, pf_schema, vf_schema);973if (rc)974device_printf(dev, "Failed to initialize SR-IOV (error=%d)\n", rc);975}976977#else978979void980bnxt_sriov_attach(struct bnxt_softc *softc __unused)981{982}983984int985bnxt_cfg_hw_sriov(struct bnxt_softc *softc __unused,986uint16_t *num_vfs __unused, bool reset __unused)987{988return (0);989}990991int992bnxt_approve_mac(struct bnxt_softc *sc __unused)993{994return (0);995}996997void998bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc __unused)999{1000}10011002bool1003bnxt_promisc_ok(struct bnxt_softc *softc __unused)1004{1005return (true);1006}10071008void1009bnxt_update_vf_mac(struct bnxt_softc *sc __unused)1010{1011}1012#endif10131014void bnxt_reenable_sriov(struct bnxt_softc *bp)1015{1016if (BNXT_PF(bp)) {1017struct bnxt_pf_info *pf = &bp->pf;1018uint16_t n = pf->active_vfs;10191020if (n)1021bnxt_cfg_hw_sriov(bp, &n, true);1022}1023}102410251026