162306a36Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation 462306a36Sopenharmony_ci * Copyright (c) 2016-2018 Broadcom Limited 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 862306a36Sopenharmony_ci * the Free Software Foundation. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/ethtool.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/netdevice.h> 1562306a36Sopenharmony_ci#include <linux/if_vlan.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci#include "bnxt_hsi.h" 1962306a36Sopenharmony_ci#include "bnxt.h" 2062306a36Sopenharmony_ci#include "bnxt_hwrm.h" 2162306a36Sopenharmony_ci#include "bnxt_ulp.h" 2262306a36Sopenharmony_ci#include "bnxt_sriov.h" 2362306a36Sopenharmony_ci#include "bnxt_vfr.h" 2462306a36Sopenharmony_ci#include "bnxt_ethtool.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#ifdef CONFIG_BNXT_SRIOV 2762306a36Sopenharmony_cistatic int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp, 2862306a36Sopenharmony_ci struct bnxt_vf_info *vf, u16 event_id) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct hwrm_fwd_async_event_cmpl_input *req; 3162306a36Sopenharmony_ci struct hwrm_async_event_cmpl *async_cmpl; 3262306a36Sopenharmony_ci int rc = 0; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FWD_ASYNC_EVENT_CMPL); 3562306a36Sopenharmony_ci if (rc) 3662306a36Sopenharmony_ci goto exit; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (vf) 3962306a36Sopenharmony_ci req->encap_async_event_target_id = cpu_to_le16(vf->fw_fid); 4062306a36Sopenharmony_ci else 4162306a36Sopenharmony_ci /* broadcast this async event to all VFs */ 4262306a36Sopenharmony_ci req->encap_async_event_target_id = cpu_to_le16(0xffff); 4362306a36Sopenharmony_ci async_cmpl = 4462306a36Sopenharmony_ci (struct hwrm_async_event_cmpl *)req->encap_async_event_cmpl; 4562306a36Sopenharmony_ci async_cmpl->type = cpu_to_le16(ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT); 4662306a36Sopenharmony_ci async_cmpl->event_id = cpu_to_le16(event_id); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 4962306a36Sopenharmony_ciexit: 5062306a36Sopenharmony_ci if (rc) 5162306a36Sopenharmony_ci netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl failed. rc:%d\n", 5262306a36Sopenharmony_ci rc); 5362306a36Sopenharmony_ci return rc; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci if (!bp->pf.active_vfs) { 5962306a36Sopenharmony_ci netdev_err(bp->dev, "vf ndo called though sriov is disabled\n"); 6062306a36Sopenharmony_ci return -EINVAL; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci if (vf_id >= bp->pf.active_vfs) { 6362306a36Sopenharmony_ci netdev_err(bp->dev, "Invalid VF id %d\n", vf_id); 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciint bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 7262306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 7362306a36Sopenharmony_ci bool old_setting = false; 7462306a36Sopenharmony_ci struct bnxt_vf_info *vf; 7562306a36Sopenharmony_ci u32 func_flags; 7662306a36Sopenharmony_ci int rc; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10701) 7962306a36Sopenharmony_ci return -ENOTSUPP; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 8262306a36Sopenharmony_ci if (rc) 8362306a36Sopenharmony_ci return rc; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 8662306a36Sopenharmony_ci if (vf->flags & BNXT_VF_SPOOFCHK) 8762306a36Sopenharmony_ci old_setting = true; 8862306a36Sopenharmony_ci if (old_setting == setting) 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (setting) 9262306a36Sopenharmony_ci func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE; 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE; 9562306a36Sopenharmony_ci /*TODO: if the driver supports VLAN filter on guest VLAN, 9662306a36Sopenharmony_ci * the spoof check should also include vlan anti-spoofing 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 9962306a36Sopenharmony_ci if (!rc) { 10062306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 10162306a36Sopenharmony_ci req->flags = cpu_to_le32(func_flags); 10262306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 10362306a36Sopenharmony_ci if (!rc) { 10462306a36Sopenharmony_ci if (setting) 10562306a36Sopenharmony_ci vf->flags |= BNXT_VF_SPOOFCHK; 10662306a36Sopenharmony_ci else 10762306a36Sopenharmony_ci vf->flags &= ~BNXT_VF_SPOOFCHK; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci return rc; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int bnxt_hwrm_func_qcfg_flags(struct bnxt *bp, struct bnxt_vf_info *vf) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct hwrm_func_qcfg_output *resp; 11662306a36Sopenharmony_ci struct hwrm_func_qcfg_input *req; 11762306a36Sopenharmony_ci int rc; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_QCFG); 12062306a36Sopenharmony_ci if (rc) 12162306a36Sopenharmony_ci return rc; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci req->fid = cpu_to_le16(BNXT_PF(bp) ? vf->fw_fid : 0xffff); 12462306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 12562306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 12662306a36Sopenharmony_ci if (!rc) 12762306a36Sopenharmony_ci vf->func_qcfg_flags = le16_to_cpu(resp->flags); 12862306a36Sopenharmony_ci hwrm_req_drop(bp, req); 12962306a36Sopenharmony_ci return rc; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cibool bnxt_is_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci if (BNXT_PF(bp) && !(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF)) 13562306a36Sopenharmony_ci return !!(vf->flags & BNXT_VF_TRUST); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci bnxt_hwrm_func_qcfg_flags(bp, vf); 13862306a36Sopenharmony_ci return !!(vf->func_qcfg_flags & FUNC_QCFG_RESP_FLAGS_TRUSTED_VF); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int bnxt_hwrm_set_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 14462306a36Sopenharmony_ci int rc; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF)) 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 15062306a36Sopenharmony_ci if (rc) 15162306a36Sopenharmony_ci return rc; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 15462306a36Sopenharmony_ci if (vf->flags & BNXT_VF_TRUST) 15562306a36Sopenharmony_ci req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE); 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_DISABLE); 15862306a36Sopenharmony_ci return hwrm_req_send(bp, req); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciint bnxt_set_vf_trust(struct net_device *dev, int vf_id, bool trusted) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 16462306a36Sopenharmony_ci struct bnxt_vf_info *vf; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (bnxt_vf_ndo_prep(bp, vf_id)) 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 17062306a36Sopenharmony_ci if (trusted) 17162306a36Sopenharmony_ci vf->flags |= BNXT_VF_TRUST; 17262306a36Sopenharmony_ci else 17362306a36Sopenharmony_ci vf->flags &= ~BNXT_VF_TRUST; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci bnxt_hwrm_set_trusted_vf(bp, vf); 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint bnxt_get_vf_config(struct net_device *dev, int vf_id, 18062306a36Sopenharmony_ci struct ifla_vf_info *ivi) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 18362306a36Sopenharmony_ci struct bnxt_vf_info *vf; 18462306a36Sopenharmony_ci int rc; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 18762306a36Sopenharmony_ci if (rc) 18862306a36Sopenharmony_ci return rc; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ivi->vf = vf_id; 19162306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (is_valid_ether_addr(vf->mac_addr)) 19462306a36Sopenharmony_ci memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN); 19562306a36Sopenharmony_ci else 19662306a36Sopenharmony_ci memcpy(&ivi->mac, vf->vf_mac_addr, ETH_ALEN); 19762306a36Sopenharmony_ci ivi->max_tx_rate = vf->max_tx_rate; 19862306a36Sopenharmony_ci ivi->min_tx_rate = vf->min_tx_rate; 19962306a36Sopenharmony_ci ivi->vlan = vf->vlan; 20062306a36Sopenharmony_ci if (vf->flags & BNXT_VF_QOS) 20162306a36Sopenharmony_ci ivi->qos = vf->vlan >> VLAN_PRIO_SHIFT; 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci ivi->qos = 0; 20462306a36Sopenharmony_ci ivi->spoofchk = !!(vf->flags & BNXT_VF_SPOOFCHK); 20562306a36Sopenharmony_ci ivi->trusted = bnxt_is_trusted_vf(bp, vf); 20662306a36Sopenharmony_ci if (!(vf->flags & BNXT_VF_LINK_FORCED)) 20762306a36Sopenharmony_ci ivi->linkstate = IFLA_VF_LINK_STATE_AUTO; 20862306a36Sopenharmony_ci else if (vf->flags & BNXT_VF_LINK_UP) 20962306a36Sopenharmony_ci ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ciint bnxt_set_vf_mac(struct net_device *dev, int vf_id, u8 *mac) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 21962306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 22062306a36Sopenharmony_ci struct bnxt_vf_info *vf; 22162306a36Sopenharmony_ci int rc; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 22462306a36Sopenharmony_ci if (rc) 22562306a36Sopenharmony_ci return rc; 22662306a36Sopenharmony_ci /* reject bc or mc mac addr, zero mac addr means allow 22762306a36Sopenharmony_ci * VF to use its own mac addr 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci if (is_multicast_ether_addr(mac)) { 23062306a36Sopenharmony_ci netdev_err(dev, "Invalid VF ethernet address\n"); 23162306a36Sopenharmony_ci return -EINVAL; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 23662306a36Sopenharmony_ci if (rc) 23762306a36Sopenharmony_ci return rc; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci memcpy(vf->mac_addr, mac, ETH_ALEN); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 24262306a36Sopenharmony_ci req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 24362306a36Sopenharmony_ci memcpy(req->dflt_mac_addr, mac, ETH_ALEN); 24462306a36Sopenharmony_ci return hwrm_req_send(bp, req); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciint bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos, 24862306a36Sopenharmony_ci __be16 vlan_proto) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 25162306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 25262306a36Sopenharmony_ci struct bnxt_vf_info *vf; 25362306a36Sopenharmony_ci u16 vlan_tag; 25462306a36Sopenharmony_ci int rc; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10201) 25762306a36Sopenharmony_ci return -ENOTSUPP; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q)) 26062306a36Sopenharmony_ci return -EPROTONOSUPPORT; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 26362306a36Sopenharmony_ci if (rc) 26462306a36Sopenharmony_ci return rc; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* TODO: needed to implement proper handling of user priority, 26762306a36Sopenharmony_ci * currently fail the command if there is valid priority 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci if (vlan_id > 4095 || qos) 27062306a36Sopenharmony_ci return -EINVAL; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 27362306a36Sopenharmony_ci vlan_tag = vlan_id; 27462306a36Sopenharmony_ci if (vlan_tag == vf->vlan) 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 27862306a36Sopenharmony_ci if (!rc) { 27962306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 28062306a36Sopenharmony_ci req->dflt_vlan = cpu_to_le16(vlan_tag); 28162306a36Sopenharmony_ci req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN); 28262306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 28362306a36Sopenharmony_ci if (!rc) 28462306a36Sopenharmony_ci vf->vlan = vlan_tag; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci return rc; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciint bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate, 29062306a36Sopenharmony_ci int max_tx_rate) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 29362306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 29462306a36Sopenharmony_ci struct bnxt_vf_info *vf; 29562306a36Sopenharmony_ci u32 pf_link_speed; 29662306a36Sopenharmony_ci int rc; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 29962306a36Sopenharmony_ci if (rc) 30062306a36Sopenharmony_ci return rc; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 30362306a36Sopenharmony_ci pf_link_speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed); 30462306a36Sopenharmony_ci if (max_tx_rate > pf_link_speed) { 30562306a36Sopenharmony_ci netdev_info(bp->dev, "max tx rate %d exceed PF link speed for VF %d\n", 30662306a36Sopenharmony_ci max_tx_rate, vf_id); 30762306a36Sopenharmony_ci return -EINVAL; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (min_tx_rate > pf_link_speed) { 31162306a36Sopenharmony_ci netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n", 31262306a36Sopenharmony_ci min_tx_rate, vf_id); 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 31862306a36Sopenharmony_ci if (!rc) { 31962306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 32062306a36Sopenharmony_ci req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW | 32162306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_MIN_BW); 32262306a36Sopenharmony_ci req->max_bw = cpu_to_le32(max_tx_rate); 32362306a36Sopenharmony_ci req->min_bw = cpu_to_le32(min_tx_rate); 32462306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 32562306a36Sopenharmony_ci if (!rc) { 32662306a36Sopenharmony_ci vf->min_tx_rate = min_tx_rate; 32762306a36Sopenharmony_ci vf->max_tx_rate = max_tx_rate; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci return rc; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ciint bnxt_set_vf_link_state(struct net_device *dev, int vf_id, int link) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 33662306a36Sopenharmony_ci struct bnxt_vf_info *vf; 33762306a36Sopenharmony_ci int rc; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci rc = bnxt_vf_ndo_prep(bp, vf_id); 34062306a36Sopenharmony_ci if (rc) 34162306a36Sopenharmony_ci return rc; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci vf->flags &= ~(BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED); 34662306a36Sopenharmony_ci switch (link) { 34762306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 34862306a36Sopenharmony_ci vf->flags |= BNXT_VF_LINK_UP; 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 35162306a36Sopenharmony_ci vf->flags |= BNXT_VF_LINK_FORCED; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 35462306a36Sopenharmony_ci vf->flags |= BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED; 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci default: 35762306a36Sopenharmony_ci netdev_err(bp->dev, "Invalid link option\n"); 35862306a36Sopenharmony_ci rc = -EINVAL; 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci if (vf->flags & (BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED)) 36262306a36Sopenharmony_ci rc = bnxt_hwrm_fwd_async_event_cmpl(bp, vf, 36362306a36Sopenharmony_ci ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE); 36462306a36Sopenharmony_ci return rc; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci struct bnxt_vf_info *vf; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 37362306a36Sopenharmony_ci vf = &bp->pf.vf[i]; 37462306a36Sopenharmony_ci memset(vf, 0, sizeof(*vf)); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct hwrm_func_vf_resc_free_input *req; 38262306a36Sopenharmony_ci struct bnxt_pf_info *pf = &bp->pf; 38362306a36Sopenharmony_ci int i, rc; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_RESC_FREE); 38662306a36Sopenharmony_ci if (rc) 38762306a36Sopenharmony_ci return rc; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci hwrm_req_hold(bp, req); 39062306a36Sopenharmony_ci for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) { 39162306a36Sopenharmony_ci req->vf_id = cpu_to_le16(i); 39262306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 39362306a36Sopenharmony_ci if (rc) 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci hwrm_req_drop(bp, req); 39762306a36Sopenharmony_ci return rc; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void bnxt_free_vf_resources(struct bnxt *bp) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 40362306a36Sopenharmony_ci int i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci kfree(bp->pf.vf_event_bmap); 40662306a36Sopenharmony_ci bp->pf.vf_event_bmap = NULL; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 40962306a36Sopenharmony_ci if (bp->pf.hwrm_cmd_req_addr[i]) { 41062306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, BNXT_PAGE_SIZE, 41162306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_addr[i], 41262306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_dma_addr[i]); 41362306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_addr[i] = NULL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci bp->pf.active_vfs = 0; 41862306a36Sopenharmony_ci kfree(bp->pf.vf); 41962306a36Sopenharmony_ci bp->pf.vf = NULL; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int bnxt_alloc_vf_resources(struct bnxt *bp, int num_vfs) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 42562306a36Sopenharmony_ci u32 nr_pages, size, i, j, k = 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci bp->pf.vf = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL); 42862306a36Sopenharmony_ci if (!bp->pf.vf) 42962306a36Sopenharmony_ci return -ENOMEM; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci bnxt_set_vf_attr(bp, num_vfs); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE; 43462306a36Sopenharmony_ci nr_pages = size / BNXT_PAGE_SIZE; 43562306a36Sopenharmony_ci if (size & (BNXT_PAGE_SIZE - 1)) 43662306a36Sopenharmony_ci nr_pages++; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 43962306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_addr[i] = 44062306a36Sopenharmony_ci dma_alloc_coherent(&pdev->dev, BNXT_PAGE_SIZE, 44162306a36Sopenharmony_ci &bp->pf.hwrm_cmd_req_dma_addr[i], 44262306a36Sopenharmony_ci GFP_KERNEL); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!bp->pf.hwrm_cmd_req_addr[i]) 44562306a36Sopenharmony_ci return -ENOMEM; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci for (j = 0; j < BNXT_HWRM_REQS_PER_PAGE && k < num_vfs; j++) { 44862306a36Sopenharmony_ci struct bnxt_vf_info *vf = &bp->pf.vf[k]; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci vf->hwrm_cmd_req_addr = bp->pf.hwrm_cmd_req_addr[i] + 45162306a36Sopenharmony_ci j * BNXT_HWRM_REQ_MAX_SIZE; 45262306a36Sopenharmony_ci vf->hwrm_cmd_req_dma_addr = 45362306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_dma_addr[i] + j * 45462306a36Sopenharmony_ci BNXT_HWRM_REQ_MAX_SIZE; 45562306a36Sopenharmony_ci k++; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Max 128 VF's */ 46062306a36Sopenharmony_ci bp->pf.vf_event_bmap = kzalloc(16, GFP_KERNEL); 46162306a36Sopenharmony_ci if (!bp->pf.vf_event_bmap) 46262306a36Sopenharmony_ci return -ENOMEM; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci bp->pf.hwrm_cmd_req_pages = nr_pages; 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct hwrm_func_buf_rgtr_input *req; 47162306a36Sopenharmony_ci int rc; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_BUF_RGTR); 47462306a36Sopenharmony_ci if (rc) 47562306a36Sopenharmony_ci return rc; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci req->req_buf_num_pages = cpu_to_le16(bp->pf.hwrm_cmd_req_pages); 47862306a36Sopenharmony_ci req->req_buf_page_size = cpu_to_le16(BNXT_PAGE_SHIFT); 47962306a36Sopenharmony_ci req->req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE); 48062306a36Sopenharmony_ci req->req_buf_page_addr0 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[0]); 48162306a36Sopenharmony_ci req->req_buf_page_addr1 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[1]); 48262306a36Sopenharmony_ci req->req_buf_page_addr2 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[2]); 48362306a36Sopenharmony_ci req->req_buf_page_addr3 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[3]); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return hwrm_req_send(bp, req); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int __bnxt_set_vf_params(struct bnxt *bp, int vf_id) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 49162306a36Sopenharmony_ci struct bnxt_vf_info *vf; 49262306a36Sopenharmony_ci int rc; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 49562306a36Sopenharmony_ci if (rc) 49662306a36Sopenharmony_ci return rc; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci vf = &bp->pf.vf[vf_id]; 49962306a36Sopenharmony_ci req->fid = cpu_to_le16(vf->fw_fid); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (is_valid_ether_addr(vf->mac_addr)) { 50262306a36Sopenharmony_ci req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 50362306a36Sopenharmony_ci memcpy(req->dflt_mac_addr, vf->mac_addr, ETH_ALEN); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci if (vf->vlan) { 50662306a36Sopenharmony_ci req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN); 50762306a36Sopenharmony_ci req->dflt_vlan = cpu_to_le16(vf->vlan); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci if (vf->max_tx_rate) { 51062306a36Sopenharmony_ci req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW | 51162306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_MIN_BW); 51262306a36Sopenharmony_ci req->max_bw = cpu_to_le32(vf->max_tx_rate); 51362306a36Sopenharmony_ci req->min_bw = cpu_to_le32(vf->min_tx_rate); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci if (vf->flags & BNXT_VF_TRUST) 51662306a36Sopenharmony_ci req->flags |= cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return hwrm_req_send(bp, req); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* Only called by PF to reserve resources for VFs, returns actual number of 52262306a36Sopenharmony_ci * VFs configured, or < 0 on error. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_cistatic int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct hwrm_func_vf_resource_cfg_input *req; 52762306a36Sopenharmony_ci struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 52862306a36Sopenharmony_ci u16 vf_tx_rings, vf_rx_rings, vf_cp_rings; 52962306a36Sopenharmony_ci u16 vf_stat_ctx, vf_vnics, vf_ring_grps; 53062306a36Sopenharmony_ci struct bnxt_pf_info *pf = &bp->pf; 53162306a36Sopenharmony_ci int i, rc = 0, min = 1; 53262306a36Sopenharmony_ci u16 vf_msix = 0; 53362306a36Sopenharmony_ci u16 vf_rss; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_RESOURCE_CFG); 53662306a36Sopenharmony_ci if (rc) 53762306a36Sopenharmony_ci return rc; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) { 54062306a36Sopenharmony_ci vf_msix = hw_resc->max_nqs - bnxt_nq_rings_in_use(bp); 54162306a36Sopenharmony_ci vf_ring_grps = 0; 54262306a36Sopenharmony_ci } else { 54362306a36Sopenharmony_ci vf_ring_grps = hw_resc->max_hw_ring_grps - bp->rx_nr_rings; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci vf_cp_rings = bnxt_get_avail_cp_rings_for_en(bp); 54662306a36Sopenharmony_ci vf_stat_ctx = bnxt_get_avail_stat_ctxs_for_en(bp); 54762306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_AGG_RINGS) 54862306a36Sopenharmony_ci vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings * 2; 54962306a36Sopenharmony_ci else 55062306a36Sopenharmony_ci vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings; 55162306a36Sopenharmony_ci vf_tx_rings = hw_resc->max_tx_rings - bp->tx_nr_rings; 55262306a36Sopenharmony_ci vf_vnics = hw_resc->max_vnics - bp->nr_vnics; 55362306a36Sopenharmony_ci vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 55462306a36Sopenharmony_ci vf_rss = hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci req->min_rsscos_ctx = cpu_to_le16(BNXT_VF_MIN_RSS_CTX); 55762306a36Sopenharmony_ci if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL_STATIC) { 55862306a36Sopenharmony_ci min = 0; 55962306a36Sopenharmony_ci req->min_rsscos_ctx = cpu_to_le16(min); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL || 56262306a36Sopenharmony_ci pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL_STATIC) { 56362306a36Sopenharmony_ci req->min_cmpl_rings = cpu_to_le16(min); 56462306a36Sopenharmony_ci req->min_tx_rings = cpu_to_le16(min); 56562306a36Sopenharmony_ci req->min_rx_rings = cpu_to_le16(min); 56662306a36Sopenharmony_ci req->min_l2_ctxs = cpu_to_le16(min); 56762306a36Sopenharmony_ci req->min_vnics = cpu_to_le16(min); 56862306a36Sopenharmony_ci req->min_stat_ctx = cpu_to_le16(min); 56962306a36Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_CHIP_P5)) 57062306a36Sopenharmony_ci req->min_hw_ring_grps = cpu_to_le16(min); 57162306a36Sopenharmony_ci } else { 57262306a36Sopenharmony_ci vf_cp_rings /= num_vfs; 57362306a36Sopenharmony_ci vf_tx_rings /= num_vfs; 57462306a36Sopenharmony_ci vf_rx_rings /= num_vfs; 57562306a36Sopenharmony_ci vf_vnics /= num_vfs; 57662306a36Sopenharmony_ci vf_stat_ctx /= num_vfs; 57762306a36Sopenharmony_ci vf_ring_grps /= num_vfs; 57862306a36Sopenharmony_ci vf_rss /= num_vfs; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci req->min_cmpl_rings = cpu_to_le16(vf_cp_rings); 58162306a36Sopenharmony_ci req->min_tx_rings = cpu_to_le16(vf_tx_rings); 58262306a36Sopenharmony_ci req->min_rx_rings = cpu_to_le16(vf_rx_rings); 58362306a36Sopenharmony_ci req->min_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); 58462306a36Sopenharmony_ci req->min_vnics = cpu_to_le16(vf_vnics); 58562306a36Sopenharmony_ci req->min_stat_ctx = cpu_to_le16(vf_stat_ctx); 58662306a36Sopenharmony_ci req->min_hw_ring_grps = cpu_to_le16(vf_ring_grps); 58762306a36Sopenharmony_ci req->min_rsscos_ctx = cpu_to_le16(vf_rss); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci req->max_cmpl_rings = cpu_to_le16(vf_cp_rings); 59062306a36Sopenharmony_ci req->max_tx_rings = cpu_to_le16(vf_tx_rings); 59162306a36Sopenharmony_ci req->max_rx_rings = cpu_to_le16(vf_rx_rings); 59262306a36Sopenharmony_ci req->max_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); 59362306a36Sopenharmony_ci req->max_vnics = cpu_to_le16(vf_vnics); 59462306a36Sopenharmony_ci req->max_stat_ctx = cpu_to_le16(vf_stat_ctx); 59562306a36Sopenharmony_ci req->max_hw_ring_grps = cpu_to_le16(vf_ring_grps); 59662306a36Sopenharmony_ci req->max_rsscos_ctx = cpu_to_le16(vf_rss); 59762306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 59862306a36Sopenharmony_ci req->max_msix = cpu_to_le16(vf_msix / num_vfs); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci hwrm_req_hold(bp, req); 60162306a36Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 60262306a36Sopenharmony_ci if (reset) 60362306a36Sopenharmony_ci __bnxt_set_vf_params(bp, i); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci req->vf_id = cpu_to_le16(pf->first_vf_id + i); 60662306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 60762306a36Sopenharmony_ci if (rc) 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci pf->active_vfs = i + 1; 61062306a36Sopenharmony_ci pf->vf[i].fw_fid = pf->first_vf_id + i; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (pf->active_vfs) { 61462306a36Sopenharmony_ci u16 n = pf->active_vfs; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci hw_resc->max_tx_rings -= le16_to_cpu(req->min_tx_rings) * n; 61762306a36Sopenharmony_ci hw_resc->max_rx_rings -= le16_to_cpu(req->min_rx_rings) * n; 61862306a36Sopenharmony_ci hw_resc->max_hw_ring_grps -= 61962306a36Sopenharmony_ci le16_to_cpu(req->min_hw_ring_grps) * n; 62062306a36Sopenharmony_ci hw_resc->max_cp_rings -= le16_to_cpu(req->min_cmpl_rings) * n; 62162306a36Sopenharmony_ci hw_resc->max_rsscos_ctxs -= 62262306a36Sopenharmony_ci le16_to_cpu(req->min_rsscos_ctx) * n; 62362306a36Sopenharmony_ci hw_resc->max_stat_ctxs -= le16_to_cpu(req->min_stat_ctx) * n; 62462306a36Sopenharmony_ci hw_resc->max_vnics -= le16_to_cpu(req->min_vnics) * n; 62562306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 62662306a36Sopenharmony_ci hw_resc->max_nqs -= vf_msix; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci rc = pf->active_vfs; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci hwrm_req_drop(bp, req); 63162306a36Sopenharmony_ci return rc; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/* Only called by PF to reserve resources for VFs, returns actual number of 63562306a36Sopenharmony_ci * VFs configured, or < 0 on error. 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_cistatic int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics; 64062306a36Sopenharmony_ci struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 64162306a36Sopenharmony_ci struct bnxt_pf_info *pf = &bp->pf; 64262306a36Sopenharmony_ci struct hwrm_func_cfg_input *req; 64362306a36Sopenharmony_ci int total_vf_tx_rings = 0; 64462306a36Sopenharmony_ci u16 vf_ring_grps; 64562306a36Sopenharmony_ci u32 mtu, i; 64662306a36Sopenharmony_ci int rc; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 64962306a36Sopenharmony_ci if (rc) 65062306a36Sopenharmony_ci return rc; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* Remaining rings are distributed equally amongs VF's for now */ 65362306a36Sopenharmony_ci vf_cp_rings = bnxt_get_avail_cp_rings_for_en(bp) / num_vfs; 65462306a36Sopenharmony_ci vf_stat_ctx = bnxt_get_avail_stat_ctxs_for_en(bp) / num_vfs; 65562306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_AGG_RINGS) 65662306a36Sopenharmony_ci vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings * 2) / 65762306a36Sopenharmony_ci num_vfs; 65862306a36Sopenharmony_ci else 65962306a36Sopenharmony_ci vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings) / 66062306a36Sopenharmony_ci num_vfs; 66162306a36Sopenharmony_ci vf_ring_grps = (hw_resc->max_hw_ring_grps - bp->rx_nr_rings) / num_vfs; 66262306a36Sopenharmony_ci vf_tx_rings = (hw_resc->max_tx_rings - bp->tx_nr_rings) / num_vfs; 66362306a36Sopenharmony_ci vf_vnics = (hw_resc->max_vnics - bp->nr_vnics) / num_vfs; 66462306a36Sopenharmony_ci vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_ADMIN_MTU | 66762306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_MRU | 66862306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS | 66962306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS | 67062306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | 67162306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS | 67262306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS | 67362306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_L2_CTXS | 67462306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_VNICS | 67562306a36Sopenharmony_ci FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci mtu = bp->dev->mtu + ETH_HLEN + VLAN_HLEN; 67862306a36Sopenharmony_ci req->mru = cpu_to_le16(mtu); 67962306a36Sopenharmony_ci req->admin_mtu = cpu_to_le16(mtu); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci req->num_rsscos_ctxs = cpu_to_le16(1); 68262306a36Sopenharmony_ci req->num_cmpl_rings = cpu_to_le16(vf_cp_rings); 68362306a36Sopenharmony_ci req->num_tx_rings = cpu_to_le16(vf_tx_rings); 68462306a36Sopenharmony_ci req->num_rx_rings = cpu_to_le16(vf_rx_rings); 68562306a36Sopenharmony_ci req->num_hw_ring_grps = cpu_to_le16(vf_ring_grps); 68662306a36Sopenharmony_ci req->num_l2_ctxs = cpu_to_le16(4); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci req->num_vnics = cpu_to_le16(vf_vnics); 68962306a36Sopenharmony_ci /* FIXME spec currently uses 1 bit for stats ctx */ 69062306a36Sopenharmony_ci req->num_stat_ctxs = cpu_to_le16(vf_stat_ctx); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci hwrm_req_hold(bp, req); 69362306a36Sopenharmony_ci for (i = 0; i < num_vfs; i++) { 69462306a36Sopenharmony_ci int vf_tx_rsvd = vf_tx_rings; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci req->fid = cpu_to_le16(pf->first_vf_id + i); 69762306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 69862306a36Sopenharmony_ci if (rc) 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci pf->active_vfs = i + 1; 70162306a36Sopenharmony_ci pf->vf[i].fw_fid = le16_to_cpu(req->fid); 70262306a36Sopenharmony_ci rc = __bnxt_hwrm_get_tx_rings(bp, pf->vf[i].fw_fid, 70362306a36Sopenharmony_ci &vf_tx_rsvd); 70462306a36Sopenharmony_ci if (rc) 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci total_vf_tx_rings += vf_tx_rsvd; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci hwrm_req_drop(bp, req); 70962306a36Sopenharmony_ci if (pf->active_vfs) { 71062306a36Sopenharmony_ci hw_resc->max_tx_rings -= total_vf_tx_rings; 71162306a36Sopenharmony_ci hw_resc->max_rx_rings -= vf_rx_rings * num_vfs; 71262306a36Sopenharmony_ci hw_resc->max_hw_ring_grps -= vf_ring_grps * num_vfs; 71362306a36Sopenharmony_ci hw_resc->max_cp_rings -= vf_cp_rings * num_vfs; 71462306a36Sopenharmony_ci hw_resc->max_rsscos_ctxs -= num_vfs; 71562306a36Sopenharmony_ci hw_resc->max_stat_ctxs -= vf_stat_ctx * num_vfs; 71662306a36Sopenharmony_ci hw_resc->max_vnics -= vf_vnics * num_vfs; 71762306a36Sopenharmony_ci rc = pf->active_vfs; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci return rc; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int bnxt_func_cfg(struct bnxt *bp, int num_vfs, bool reset) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci if (BNXT_NEW_RM(bp)) 72562306a36Sopenharmony_ci return bnxt_hwrm_func_vf_resc_cfg(bp, num_vfs, reset); 72662306a36Sopenharmony_ci else 72762306a36Sopenharmony_ci return bnxt_hwrm_func_cfg(bp, num_vfs); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ciint bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci int rc; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* Register buffers for VFs */ 73562306a36Sopenharmony_ci rc = bnxt_hwrm_func_buf_rgtr(bp); 73662306a36Sopenharmony_ci if (rc) 73762306a36Sopenharmony_ci return rc; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Reserve resources for VFs */ 74062306a36Sopenharmony_ci rc = bnxt_func_cfg(bp, *num_vfs, reset); 74162306a36Sopenharmony_ci if (rc != *num_vfs) { 74262306a36Sopenharmony_ci if (rc <= 0) { 74362306a36Sopenharmony_ci netdev_warn(bp->dev, "Unable to reserve resources for SRIOV.\n"); 74462306a36Sopenharmony_ci *num_vfs = 0; 74562306a36Sopenharmony_ci return rc; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci netdev_warn(bp->dev, "Only able to reserve resources for %d VFs.\n", 74862306a36Sopenharmony_ci rc); 74962306a36Sopenharmony_ci *num_vfs = rc; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci int rc = 0, vfs_supported; 75862306a36Sopenharmony_ci int min_rx_rings, min_tx_rings, min_rss_ctxs; 75962306a36Sopenharmony_ci struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 76062306a36Sopenharmony_ci int tx_ok = 0, rx_ok = 0, rss_ok = 0; 76162306a36Sopenharmony_ci int avail_cp, avail_stat; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Check if we can enable requested num of vf's. At a mininum 76462306a36Sopenharmony_ci * we require 1 RX 1 TX rings for each VF. In this minimum conf 76562306a36Sopenharmony_ci * features like TPA will not be available. 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_ci vfs_supported = *num_vfs; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci avail_cp = bnxt_get_avail_cp_rings_for_en(bp); 77062306a36Sopenharmony_ci avail_stat = bnxt_get_avail_stat_ctxs_for_en(bp); 77162306a36Sopenharmony_ci avail_cp = min_t(int, avail_cp, avail_stat); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci while (vfs_supported) { 77462306a36Sopenharmony_ci min_rx_rings = vfs_supported; 77562306a36Sopenharmony_ci min_tx_rings = vfs_supported; 77662306a36Sopenharmony_ci min_rss_ctxs = vfs_supported; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_AGG_RINGS) { 77962306a36Sopenharmony_ci if (hw_resc->max_rx_rings - bp->rx_nr_rings * 2 >= 78062306a36Sopenharmony_ci min_rx_rings) 78162306a36Sopenharmony_ci rx_ok = 1; 78262306a36Sopenharmony_ci } else { 78362306a36Sopenharmony_ci if (hw_resc->max_rx_rings - bp->rx_nr_rings >= 78462306a36Sopenharmony_ci min_rx_rings) 78562306a36Sopenharmony_ci rx_ok = 1; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci if (hw_resc->max_vnics - bp->nr_vnics < min_rx_rings || 78862306a36Sopenharmony_ci avail_cp < min_rx_rings) 78962306a36Sopenharmony_ci rx_ok = 0; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (hw_resc->max_tx_rings - bp->tx_nr_rings >= min_tx_rings && 79262306a36Sopenharmony_ci avail_cp >= min_tx_rings) 79362306a36Sopenharmony_ci tx_ok = 1; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs >= 79662306a36Sopenharmony_ci min_rss_ctxs) 79762306a36Sopenharmony_ci rss_ok = 1; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (tx_ok && rx_ok && rss_ok) 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci vfs_supported--; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (!vfs_supported) { 80662306a36Sopenharmony_ci netdev_err(bp->dev, "Cannot enable VF's as all resources are used by PF\n"); 80762306a36Sopenharmony_ci return -EINVAL; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (vfs_supported != *num_vfs) { 81162306a36Sopenharmony_ci netdev_info(bp->dev, "Requested VFs %d, can enable %d\n", 81262306a36Sopenharmony_ci *num_vfs, vfs_supported); 81362306a36Sopenharmony_ci *num_vfs = vfs_supported; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci rc = bnxt_alloc_vf_resources(bp, *num_vfs); 81762306a36Sopenharmony_ci if (rc) 81862306a36Sopenharmony_ci goto err_out1; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci rc = bnxt_cfg_hw_sriov(bp, num_vfs, false); 82162306a36Sopenharmony_ci if (rc) 82262306a36Sopenharmony_ci goto err_out2; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci rc = pci_enable_sriov(bp->pdev, *num_vfs); 82562306a36Sopenharmony_ci if (rc) 82662306a36Sopenharmony_ci goto err_out2; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 82962306a36Sopenharmony_ci return 0; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Create representors for VFs in switchdev mode */ 83262306a36Sopenharmony_ci devl_lock(bp->dl); 83362306a36Sopenharmony_ci rc = bnxt_vf_reps_create(bp); 83462306a36Sopenharmony_ci devl_unlock(bp->dl); 83562306a36Sopenharmony_ci if (rc) { 83662306a36Sopenharmony_ci netdev_info(bp->dev, "Cannot enable VFS as representors cannot be created\n"); 83762306a36Sopenharmony_ci goto err_out3; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cierr_out3: 84362306a36Sopenharmony_ci /* Disable SR-IOV */ 84462306a36Sopenharmony_ci pci_disable_sriov(bp->pdev); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cierr_out2: 84762306a36Sopenharmony_ci /* Free the resources reserved for various VF's */ 84862306a36Sopenharmony_ci bnxt_hwrm_func_vf_resource_free(bp, *num_vfs); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Restore the max resources */ 85162306a36Sopenharmony_ci bnxt_hwrm_func_qcaps(bp); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cierr_out1: 85462306a36Sopenharmony_ci bnxt_free_vf_resources(bp); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return rc; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_civoid bnxt_sriov_disable(struct bnxt *bp) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci u16 num_vfs = pci_num_vf(bp->pdev); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (!num_vfs) 86462306a36Sopenharmony_ci return; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* synchronize VF and VF-rep create and destroy */ 86762306a36Sopenharmony_ci devl_lock(bp->dl); 86862306a36Sopenharmony_ci bnxt_vf_reps_destroy(bp); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (pci_vfs_assigned(bp->pdev)) { 87162306a36Sopenharmony_ci bnxt_hwrm_fwd_async_event_cmpl( 87262306a36Sopenharmony_ci bp, NULL, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD); 87362306a36Sopenharmony_ci netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n", 87462306a36Sopenharmony_ci num_vfs); 87562306a36Sopenharmony_ci } else { 87662306a36Sopenharmony_ci pci_disable_sriov(bp->pdev); 87762306a36Sopenharmony_ci /* Free the HW resources reserved for various VF's */ 87862306a36Sopenharmony_ci bnxt_hwrm_func_vf_resource_free(bp, num_vfs); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci devl_unlock(bp->dl); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci bnxt_free_vf_resources(bp); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* Reclaim all resources for the PF. */ 88562306a36Sopenharmony_ci rtnl_lock(); 88662306a36Sopenharmony_ci bnxt_restore_pf_fw_resources(bp); 88762306a36Sopenharmony_ci rtnl_unlock(); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ciint bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 89362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_USING_MSIX)) { 89662306a36Sopenharmony_ci netdev_warn(dev, "Not allow SRIOV if the irq mode is not MSIX\n"); 89762306a36Sopenharmony_ci return 0; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci rtnl_lock(); 90162306a36Sopenharmony_ci if (!netif_running(dev)) { 90262306a36Sopenharmony_ci netdev_warn(dev, "Reject SRIOV config request since if is down!\n"); 90362306a36Sopenharmony_ci rtnl_unlock(); 90462306a36Sopenharmony_ci return 0; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { 90762306a36Sopenharmony_ci netdev_warn(dev, "Reject SRIOV config request when FW reset is in progress\n"); 90862306a36Sopenharmony_ci rtnl_unlock(); 90962306a36Sopenharmony_ci return 0; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci bp->sriov_cfg = true; 91262306a36Sopenharmony_ci rtnl_unlock(); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (pci_vfs_assigned(bp->pdev)) { 91562306a36Sopenharmony_ci netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n"); 91662306a36Sopenharmony_ci num_vfs = 0; 91762306a36Sopenharmony_ci goto sriov_cfg_exit; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* Check if enabled VFs is same as requested */ 92162306a36Sopenharmony_ci if (num_vfs && num_vfs == bp->pf.active_vfs) 92262306a36Sopenharmony_ci goto sriov_cfg_exit; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* if there are previous existing VFs, clean them up */ 92562306a36Sopenharmony_ci bnxt_sriov_disable(bp); 92662306a36Sopenharmony_ci if (!num_vfs) 92762306a36Sopenharmony_ci goto sriov_cfg_exit; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci bnxt_sriov_enable(bp, &num_vfs); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cisriov_cfg_exit: 93262306a36Sopenharmony_ci bp->sriov_cfg = false; 93362306a36Sopenharmony_ci wake_up(&bp->sriov_cfg_wait); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci return num_vfs; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 93962306a36Sopenharmony_ci void *encap_resp, __le64 encap_resp_addr, 94062306a36Sopenharmony_ci __le16 encap_resp_cpr, u32 msg_size) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct hwrm_fwd_resp_input *req; 94362306a36Sopenharmony_ci int rc; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (BNXT_FWD_RESP_SIZE_ERR(msg_size)) 94662306a36Sopenharmony_ci return -EINVAL; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FWD_RESP); 94962306a36Sopenharmony_ci if (!rc) { 95062306a36Sopenharmony_ci /* Set the new target id */ 95162306a36Sopenharmony_ci req->target_id = cpu_to_le16(vf->fw_fid); 95262306a36Sopenharmony_ci req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 95362306a36Sopenharmony_ci req->encap_resp_len = cpu_to_le16(msg_size); 95462306a36Sopenharmony_ci req->encap_resp_addr = encap_resp_addr; 95562306a36Sopenharmony_ci req->encap_resp_cmpl_ring = encap_resp_cpr; 95662306a36Sopenharmony_ci memcpy(req->encap_resp, encap_resp, msg_size); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci if (rc) 96162306a36Sopenharmony_ci netdev_err(bp->dev, "hwrm_fwd_resp failed. rc:%d\n", rc); 96262306a36Sopenharmony_ci return rc; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int bnxt_hwrm_fwd_err_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 96662306a36Sopenharmony_ci u32 msg_size) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct hwrm_reject_fwd_resp_input *req; 96962306a36Sopenharmony_ci int rc; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (BNXT_REJ_FWD_RESP_SIZE_ERR(msg_size)) 97262306a36Sopenharmony_ci return -EINVAL; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_REJECT_FWD_RESP); 97562306a36Sopenharmony_ci if (!rc) { 97662306a36Sopenharmony_ci /* Set the new target id */ 97762306a36Sopenharmony_ci req->target_id = cpu_to_le16(vf->fw_fid); 97862306a36Sopenharmony_ci req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 97962306a36Sopenharmony_ci memcpy(req->encap_request, vf->hwrm_cmd_req_addr, msg_size); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci if (rc) 98462306a36Sopenharmony_ci netdev_err(bp->dev, "hwrm_fwd_err_resp failed. rc:%d\n", rc); 98562306a36Sopenharmony_ci return rc; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 98962306a36Sopenharmony_ci u32 msg_size) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct hwrm_exec_fwd_resp_input *req; 99262306a36Sopenharmony_ci int rc; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (BNXT_EXEC_FWD_RESP_SIZE_ERR(msg_size)) 99562306a36Sopenharmony_ci return -EINVAL; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_EXEC_FWD_RESP); 99862306a36Sopenharmony_ci if (!rc) { 99962306a36Sopenharmony_ci /* Set the new target id */ 100062306a36Sopenharmony_ci req->target_id = cpu_to_le16(vf->fw_fid); 100162306a36Sopenharmony_ci req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 100262306a36Sopenharmony_ci memcpy(req->encap_request, vf->hwrm_cmd_req_addr, msg_size); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci if (rc) 100762306a36Sopenharmony_ci netdev_err(bp->dev, "hwrm_exec_fw_resp failed. rc:%d\n", rc); 100862306a36Sopenharmony_ci return rc; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int bnxt_vf_configure_mac(struct bnxt *bp, struct bnxt_vf_info *vf) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input); 101462306a36Sopenharmony_ci struct hwrm_func_vf_cfg_input *req = 101562306a36Sopenharmony_ci (struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* Allow VF to set a valid MAC address, if trust is set to on or 101862306a36Sopenharmony_ci * if the PF assigned MAC address is zero 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ci if (req->enables & cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)) { 102162306a36Sopenharmony_ci bool trust = bnxt_is_trusted_vf(bp, vf); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (is_valid_ether_addr(req->dflt_mac_addr) && 102462306a36Sopenharmony_ci (trust || !is_valid_ether_addr(vf->mac_addr) || 102562306a36Sopenharmony_ci ether_addr_equal(req->dflt_mac_addr, vf->mac_addr))) { 102662306a36Sopenharmony_ci ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr); 102762306a36Sopenharmony_ci return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input); 103762306a36Sopenharmony_ci struct hwrm_cfa_l2_filter_alloc_input *req = 103862306a36Sopenharmony_ci (struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr; 103962306a36Sopenharmony_ci bool mac_ok = false; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (!is_valid_ether_addr((const u8 *)req->l2_addr)) 104262306a36Sopenharmony_ci return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Allow VF to set a valid MAC address, if trust is set to on. 104562306a36Sopenharmony_ci * Or VF MAC address must first match MAC address in PF's context. 104662306a36Sopenharmony_ci * Otherwise, it must match the VF MAC address if firmware spec >= 104762306a36Sopenharmony_ci * 1.2.2 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci if (bnxt_is_trusted_vf(bp, vf)) { 105062306a36Sopenharmony_ci mac_ok = true; 105162306a36Sopenharmony_ci } else if (is_valid_ether_addr(vf->mac_addr)) { 105262306a36Sopenharmony_ci if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr)) 105362306a36Sopenharmony_ci mac_ok = true; 105462306a36Sopenharmony_ci } else if (is_valid_ether_addr(vf->vf_mac_addr)) { 105562306a36Sopenharmony_ci if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr)) 105662306a36Sopenharmony_ci mac_ok = true; 105762306a36Sopenharmony_ci } else { 105862306a36Sopenharmony_ci /* There are two cases: 105962306a36Sopenharmony_ci * 1.If firmware spec < 0x10202,VF MAC address is not forwarded 106062306a36Sopenharmony_ci * to the PF and so it doesn't have to match 106162306a36Sopenharmony_ci * 2.Allow VF to modify it's own MAC when PF has not assigned a 106262306a36Sopenharmony_ci * valid MAC address and firmware spec >= 0x10202 106362306a36Sopenharmony_ci */ 106462306a36Sopenharmony_ci mac_ok = true; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci if (mac_ok) 106762306a36Sopenharmony_ci return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 106862306a36Sopenharmony_ci return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci int rc = 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (!(vf->flags & BNXT_VF_LINK_FORCED)) { 107662306a36Sopenharmony_ci /* real link */ 107762306a36Sopenharmony_ci rc = bnxt_hwrm_exec_fwd_resp( 107862306a36Sopenharmony_ci bp, vf, sizeof(struct hwrm_port_phy_qcfg_input)); 107962306a36Sopenharmony_ci } else { 108062306a36Sopenharmony_ci struct hwrm_port_phy_qcfg_output phy_qcfg_resp = {0}; 108162306a36Sopenharmony_ci struct hwrm_port_phy_qcfg_input *phy_qcfg_req; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci phy_qcfg_req = 108462306a36Sopenharmony_ci (struct hwrm_port_phy_qcfg_input *)vf->hwrm_cmd_req_addr; 108562306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 108662306a36Sopenharmony_ci memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp, 108762306a36Sopenharmony_ci sizeof(phy_qcfg_resp)); 108862306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 108962306a36Sopenharmony_ci phy_qcfg_resp.resp_len = cpu_to_le16(sizeof(phy_qcfg_resp)); 109062306a36Sopenharmony_ci phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id; 109162306a36Sopenharmony_ci phy_qcfg_resp.valid = 1; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (vf->flags & BNXT_VF_LINK_UP) { 109462306a36Sopenharmony_ci /* if physical link is down, force link up on VF */ 109562306a36Sopenharmony_ci if (phy_qcfg_resp.link != 109662306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_LINK_LINK) { 109762306a36Sopenharmony_ci phy_qcfg_resp.link = 109862306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_LINK_LINK; 109962306a36Sopenharmony_ci phy_qcfg_resp.link_speed = cpu_to_le16( 110062306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_LINK_SPEED_10GB); 110162306a36Sopenharmony_ci phy_qcfg_resp.duplex_cfg = 110262306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL; 110362306a36Sopenharmony_ci phy_qcfg_resp.duplex_state = 110462306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL; 110562306a36Sopenharmony_ci phy_qcfg_resp.pause = 110662306a36Sopenharmony_ci (PORT_PHY_QCFG_RESP_PAUSE_TX | 110762306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_PAUSE_RX); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci /* force link down */ 111162306a36Sopenharmony_ci phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK; 111262306a36Sopenharmony_ci phy_qcfg_resp.link_speed = 0; 111362306a36Sopenharmony_ci phy_qcfg_resp.duplex_state = 111462306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF; 111562306a36Sopenharmony_ci phy_qcfg_resp.pause = 0; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp, 111862306a36Sopenharmony_ci phy_qcfg_req->resp_addr, 111962306a36Sopenharmony_ci phy_qcfg_req->cmpl_ring, 112062306a36Sopenharmony_ci sizeof(phy_qcfg_resp)); 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci return rc; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci int rc = 0; 112862306a36Sopenharmony_ci struct input *encap_req = vf->hwrm_cmd_req_addr; 112962306a36Sopenharmony_ci u32 req_type = le16_to_cpu(encap_req->req_type); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci switch (req_type) { 113262306a36Sopenharmony_ci case HWRM_FUNC_VF_CFG: 113362306a36Sopenharmony_ci rc = bnxt_vf_configure_mac(bp, vf); 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci case HWRM_CFA_L2_FILTER_ALLOC: 113662306a36Sopenharmony_ci rc = bnxt_vf_validate_set_mac(bp, vf); 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci case HWRM_FUNC_CFG: 113962306a36Sopenharmony_ci /* TODO Validate if VF is allowed to change mac address, 114062306a36Sopenharmony_ci * mtu, num of rings etc 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_ci rc = bnxt_hwrm_exec_fwd_resp( 114362306a36Sopenharmony_ci bp, vf, sizeof(struct hwrm_func_cfg_input)); 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci case HWRM_PORT_PHY_QCFG: 114662306a36Sopenharmony_ci rc = bnxt_vf_set_link(bp, vf); 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci default: 114962306a36Sopenharmony_ci break; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci return rc; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_civoid bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci u32 i = 0, active_vfs = bp->pf.active_vfs, vf_id; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Scan through VF's and process commands */ 115962306a36Sopenharmony_ci while (1) { 116062306a36Sopenharmony_ci vf_id = find_next_bit(bp->pf.vf_event_bmap, active_vfs, i); 116162306a36Sopenharmony_ci if (vf_id >= active_vfs) 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci clear_bit(vf_id, bp->pf.vf_event_bmap); 116562306a36Sopenharmony_ci bnxt_vf_req_validate_snd(bp, &bp->pf.vf[vf_id]); 116662306a36Sopenharmony_ci i = vf_id + 1; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ciint bnxt_approve_mac(struct bnxt *bp, const u8 *mac, bool strict) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct hwrm_func_vf_cfg_input *req; 117362306a36Sopenharmony_ci int rc = 0; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!BNXT_VF(bp)) 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10202) { 117962306a36Sopenharmony_ci if (is_valid_ether_addr(bp->vf.mac_addr)) 118062306a36Sopenharmony_ci rc = -EADDRNOTAVAIL; 118162306a36Sopenharmony_ci goto mac_done; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_CFG); 118562306a36Sopenharmony_ci if (rc) 118662306a36Sopenharmony_ci goto mac_done; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci req->enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 118962306a36Sopenharmony_ci memcpy(req->dflt_mac_addr, mac, ETH_ALEN); 119062306a36Sopenharmony_ci if (!strict) 119162306a36Sopenharmony_ci hwrm_req_flags(bp, req, BNXT_HWRM_CTX_SILENT); 119262306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 119362306a36Sopenharmony_cimac_done: 119462306a36Sopenharmony_ci if (rc && strict) { 119562306a36Sopenharmony_ci rc = -EADDRNOTAVAIL; 119662306a36Sopenharmony_ci netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", 119762306a36Sopenharmony_ci mac); 119862306a36Sopenharmony_ci return rc; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_civoid bnxt_update_vf_mac(struct bnxt *bp) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct hwrm_func_qcaps_output *resp; 120662306a36Sopenharmony_ci struct hwrm_func_qcaps_input *req; 120762306a36Sopenharmony_ci bool inform_pf = false; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (hwrm_req_init(bp, req, HWRM_FUNC_QCAPS)) 121062306a36Sopenharmony_ci return; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci req->fid = cpu_to_le16(0xffff); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 121562306a36Sopenharmony_ci if (hwrm_req_send(bp, req)) 121662306a36Sopenharmony_ci goto update_vf_mac_exit; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* Store MAC address from the firmware. There are 2 cases: 121962306a36Sopenharmony_ci * 1. MAC address is valid. It is assigned from the PF and we 122062306a36Sopenharmony_ci * need to override the current VF MAC address with it. 122162306a36Sopenharmony_ci * 2. MAC address is zero. The VF will use a random MAC address by 122262306a36Sopenharmony_ci * default but the stored zero MAC will allow the VF user to change 122362306a36Sopenharmony_ci * the random MAC address using ndo_set_mac_address() if he wants. 122462306a36Sopenharmony_ci */ 122562306a36Sopenharmony_ci if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr)) { 122662306a36Sopenharmony_ci memcpy(bp->vf.mac_addr, resp->mac_address, ETH_ALEN); 122762306a36Sopenharmony_ci /* This means we are now using our own MAC address, let 122862306a36Sopenharmony_ci * the PF know about this MAC address. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci if (!is_valid_ether_addr(bp->vf.mac_addr)) 123162306a36Sopenharmony_ci inform_pf = true; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* overwrite netdev dev_addr with admin VF MAC */ 123562306a36Sopenharmony_ci if (is_valid_ether_addr(bp->vf.mac_addr)) 123662306a36Sopenharmony_ci eth_hw_addr_set(bp->dev, bp->vf.mac_addr); 123762306a36Sopenharmony_ciupdate_vf_mac_exit: 123862306a36Sopenharmony_ci hwrm_req_drop(bp, req); 123962306a36Sopenharmony_ci if (inform_pf) 124062306a36Sopenharmony_ci bnxt_approve_mac(bp, bp->dev->dev_addr, false); 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci#else 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ciint bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci if (*num_vfs) 124862306a36Sopenharmony_ci return -EOPNOTSUPP; 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_civoid bnxt_sriov_disable(struct bnxt *bp) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_civoid bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci netdev_err(bp->dev, "Invalid VF message received when SRIOV is not enable\n"); 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_civoid bnxt_update_vf_mac(struct bnxt *bp) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ciint bnxt_approve_mac(struct bnxt *bp, const u8 *mac, bool strict) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci return 0; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci#endif 1270