1c0c050c5SMichael Chan /* Broadcom NetXtreme-C/E network driver. 2c0c050c5SMichael Chan * 311f15ed3SMichael Chan * Copyright (c) 2014-2016 Broadcom Corporation 4746df139SVasundhara Volam * Copyright (c) 2016-2018 Broadcom Limited 5c0c050c5SMichael Chan * 6c0c050c5SMichael Chan * This program is free software; you can redistribute it and/or modify 7c0c050c5SMichael Chan * it under the terms of the GNU General Public License as published by 8c0c050c5SMichael Chan * the Free Software Foundation. 9c0c050c5SMichael Chan */ 10c0c050c5SMichael Chan 11cc69837fSJakub Kicinski #include <linux/ethtool.h> 12c0c050c5SMichael Chan #include <linux/module.h> 13c0c050c5SMichael Chan #include <linux/pci.h> 14c0c050c5SMichael Chan #include <linux/netdevice.h> 15c0c050c5SMichael Chan #include <linux/if_vlan.h> 16c0c050c5SMichael Chan #include <linux/interrupt.h> 17c0c050c5SMichael Chan #include <linux/etherdevice.h> 18c0c050c5SMichael Chan #include "bnxt_hsi.h" 19c0c050c5SMichael Chan #include "bnxt.h" 203c8c20dbSEdwin Peer #include "bnxt_hwrm.h" 212f593846SMichael Chan #include "bnxt_ulp.h" 22c0c050c5SMichael Chan #include "bnxt_sriov.h" 234ab0c6a8SSathya Perla #include "bnxt_vfr.h" 24c0c050c5SMichael Chan #include "bnxt_ethtool.h" 25c0c050c5SMichael Chan 26c0c050c5SMichael Chan #ifdef CONFIG_BNXT_SRIOV 27350a7149SEddie Wai static int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp, 28350a7149SEddie Wai struct bnxt_vf_info *vf, u16 event_id) 29350a7149SEddie Wai { 30bbf33d1dSEdwin Peer struct hwrm_fwd_async_event_cmpl_input *req; 31350a7149SEddie Wai struct hwrm_async_event_cmpl *async_cmpl; 32350a7149SEddie Wai int rc = 0; 33350a7149SEddie Wai 34bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FWD_ASYNC_EVENT_CMPL); 35bbf33d1dSEdwin Peer if (rc) 36bbf33d1dSEdwin Peer goto exit; 37bbf33d1dSEdwin Peer 38350a7149SEddie Wai if (vf) 39bbf33d1dSEdwin Peer req->encap_async_event_target_id = cpu_to_le16(vf->fw_fid); 40350a7149SEddie Wai else 41350a7149SEddie Wai /* broadcast this async event to all VFs */ 42bbf33d1dSEdwin Peer req->encap_async_event_target_id = cpu_to_le16(0xffff); 43bbf33d1dSEdwin Peer async_cmpl = 44bbf33d1dSEdwin Peer (struct hwrm_async_event_cmpl *)req->encap_async_event_cmpl; 4587c374deSMichael Chan async_cmpl->type = cpu_to_le16(ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT); 46350a7149SEddie Wai async_cmpl->event_id = cpu_to_le16(event_id); 47350a7149SEddie Wai 48bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 49bbf33d1dSEdwin Peer exit: 50a798302dSMichael Chan if (rc) 51350a7149SEddie Wai netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl failed. rc:%d\n", 52350a7149SEddie Wai rc); 53350a7149SEddie Wai return rc; 54350a7149SEddie Wai } 55350a7149SEddie Wai 56c0c050c5SMichael Chan static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id) 57c0c050c5SMichael Chan { 58c0c050c5SMichael Chan if (!bp->pf.active_vfs) { 59c0c050c5SMichael Chan netdev_err(bp->dev, "vf ndo called though sriov is disabled\n"); 60c0c050c5SMichael Chan return -EINVAL; 61c0c050c5SMichael Chan } 6278f30004SVenkat Duvvuru if (vf_id >= bp->pf.active_vfs) { 63c0c050c5SMichael Chan netdev_err(bp->dev, "Invalid VF id %d\n", vf_id); 64c0c050c5SMichael Chan return -EINVAL; 65c0c050c5SMichael Chan } 66c0c050c5SMichael Chan return 0; 67c0c050c5SMichael Chan } 68c0c050c5SMichael Chan 69c0c050c5SMichael Chan int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting) 70c0c050c5SMichael Chan { 71c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 72bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 73c0c050c5SMichael Chan bool old_setting = false; 74bbf33d1dSEdwin Peer struct bnxt_vf_info *vf; 75c0c050c5SMichael Chan u32 func_flags; 76c0c050c5SMichael Chan int rc; 77c0c050c5SMichael Chan 788eb992e8SMichael Chan if (bp->hwrm_spec_code < 0x10701) 798eb992e8SMichael Chan return -ENOTSUPP; 808eb992e8SMichael Chan 81c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 82c0c050c5SMichael Chan if (rc) 83c0c050c5SMichael Chan return rc; 84c0c050c5SMichael Chan 85c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 86c0c050c5SMichael Chan if (vf->flags & BNXT_VF_SPOOFCHK) 87c0c050c5SMichael Chan old_setting = true; 88c0c050c5SMichael Chan if (old_setting == setting) 89c0c050c5SMichael Chan return 0; 90c0c050c5SMichael Chan 91c0c050c5SMichael Chan if (setting) 92c71c4e49SMichael Chan func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE; 93c0c050c5SMichael Chan else 94c71c4e49SMichael Chan func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE; 95c0c050c5SMichael Chan /*TODO: if the driver supports VLAN filter on guest VLAN, 96c0c050c5SMichael Chan * the spoof check should also include vlan anti-spoofing 97c0c050c5SMichael Chan */ 98bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 99bbf33d1dSEdwin Peer if (!rc) { 100bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 101bbf33d1dSEdwin Peer req->flags = cpu_to_le32(func_flags); 102bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 103c0c050c5SMichael Chan if (!rc) { 104c0c050c5SMichael Chan if (setting) 105c0c050c5SMichael Chan vf->flags |= BNXT_VF_SPOOFCHK; 106c0c050c5SMichael Chan else 107c0c050c5SMichael Chan vf->flags &= ~BNXT_VF_SPOOFCHK; 108c0c050c5SMichael Chan } 109bbf33d1dSEdwin Peer } 110c0c050c5SMichael Chan return rc; 111c0c050c5SMichael Chan } 112c0c050c5SMichael Chan 1132a516444SMichael Chan static int bnxt_hwrm_func_qcfg_flags(struct bnxt *bp, struct bnxt_vf_info *vf) 1142a516444SMichael Chan { 115bbf33d1dSEdwin Peer struct hwrm_func_qcfg_output *resp; 116bbf33d1dSEdwin Peer struct hwrm_func_qcfg_input *req; 1172a516444SMichael Chan int rc; 1182a516444SMichael Chan 119bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_QCFG); 120bbf33d1dSEdwin Peer if (rc) 121d4f1420dSMichael Chan return rc; 122bbf33d1dSEdwin Peer 123bbf33d1dSEdwin Peer req->fid = cpu_to_le16(BNXT_PF(bp) ? vf->fw_fid : 0xffff); 124bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 125bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 126bbf33d1dSEdwin Peer if (!rc) 1272a516444SMichael Chan vf->func_qcfg_flags = le16_to_cpu(resp->flags); 128bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 129bbf33d1dSEdwin Peer return rc; 1302a516444SMichael Chan } 1312a516444SMichael Chan 132dd85fc0aSEdwin Peer bool bnxt_is_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf) 1332a516444SMichael Chan { 134dd85fc0aSEdwin Peer if (BNXT_PF(bp) && !(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF)) 1352a516444SMichael Chan return !!(vf->flags & BNXT_VF_TRUST); 1362a516444SMichael Chan 1372a516444SMichael Chan bnxt_hwrm_func_qcfg_flags(bp, vf); 1382a516444SMichael Chan return !!(vf->func_qcfg_flags & FUNC_QCFG_RESP_FLAGS_TRUSTED_VF); 1392a516444SMichael Chan } 1402a516444SMichael Chan 1412a516444SMichael Chan static int bnxt_hwrm_set_trusted_vf(struct bnxt *bp, struct bnxt_vf_info *vf) 1422a516444SMichael Chan { 143bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 144bbf33d1dSEdwin Peer int rc; 1452a516444SMichael Chan 1462a516444SMichael Chan if (!(bp->fw_cap & BNXT_FW_CAP_TRUSTED_VF)) 1472a516444SMichael Chan return 0; 1482a516444SMichael Chan 149bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 150bbf33d1dSEdwin Peer if (rc) 151bbf33d1dSEdwin Peer return rc; 152bbf33d1dSEdwin Peer 153bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 1542a516444SMichael Chan if (vf->flags & BNXT_VF_TRUST) 155bbf33d1dSEdwin Peer req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE); 1562a516444SMichael Chan else 157bbf33d1dSEdwin Peer req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_DISABLE); 158bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 1592a516444SMichael Chan } 1602a516444SMichael Chan 161746df139SVasundhara Volam int bnxt_set_vf_trust(struct net_device *dev, int vf_id, bool trusted) 162746df139SVasundhara Volam { 163746df139SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 164746df139SVasundhara Volam struct bnxt_vf_info *vf; 165746df139SVasundhara Volam 166746df139SVasundhara Volam if (bnxt_vf_ndo_prep(bp, vf_id)) 167746df139SVasundhara Volam return -EINVAL; 168746df139SVasundhara Volam 169746df139SVasundhara Volam vf = &bp->pf.vf[vf_id]; 170746df139SVasundhara Volam if (trusted) 171746df139SVasundhara Volam vf->flags |= BNXT_VF_TRUST; 172746df139SVasundhara Volam else 173746df139SVasundhara Volam vf->flags &= ~BNXT_VF_TRUST; 174746df139SVasundhara Volam 1752a516444SMichael Chan bnxt_hwrm_set_trusted_vf(bp, vf); 176746df139SVasundhara Volam return 0; 177746df139SVasundhara Volam } 178746df139SVasundhara Volam 179c0c050c5SMichael Chan int bnxt_get_vf_config(struct net_device *dev, int vf_id, 180c0c050c5SMichael Chan struct ifla_vf_info *ivi) 181c0c050c5SMichael Chan { 182c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 183c0c050c5SMichael Chan struct bnxt_vf_info *vf; 184c0c050c5SMichael Chan int rc; 185c0c050c5SMichael Chan 186c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 187c0c050c5SMichael Chan if (rc) 188c0c050c5SMichael Chan return rc; 189c0c050c5SMichael Chan 190c0c050c5SMichael Chan ivi->vf = vf_id; 191c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 192c0c050c5SMichael Chan 19391cdda40SVasundhara Volam if (is_valid_ether_addr(vf->mac_addr)) 194c0c050c5SMichael Chan memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN); 19591cdda40SVasundhara Volam else 19691cdda40SVasundhara Volam memcpy(&ivi->mac, vf->vf_mac_addr, ETH_ALEN); 197c0c050c5SMichael Chan ivi->max_tx_rate = vf->max_tx_rate; 198c0c050c5SMichael Chan ivi->min_tx_rate = vf->min_tx_rate; 199c0c050c5SMichael Chan ivi->vlan = vf->vlan; 200f0249056SMichael Chan if (vf->flags & BNXT_VF_QOS) 201f0249056SMichael Chan ivi->qos = vf->vlan >> VLAN_PRIO_SHIFT; 202f0249056SMichael Chan else 203f0249056SMichael Chan ivi->qos = 0; 204f0249056SMichael Chan ivi->spoofchk = !!(vf->flags & BNXT_VF_SPOOFCHK); 2052a516444SMichael Chan ivi->trusted = bnxt_is_trusted_vf(bp, vf); 206c0c050c5SMichael Chan if (!(vf->flags & BNXT_VF_LINK_FORCED)) 207c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_AUTO; 208c0c050c5SMichael Chan else if (vf->flags & BNXT_VF_LINK_UP) 209c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; 210c0c050c5SMichael Chan else 211c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; 212c0c050c5SMichael Chan 213c0c050c5SMichael Chan return 0; 214c0c050c5SMichael Chan } 215c0c050c5SMichael Chan 216c0c050c5SMichael Chan int bnxt_set_vf_mac(struct net_device *dev, int vf_id, u8 *mac) 217c0c050c5SMichael Chan { 218c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 219bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 220c0c050c5SMichael Chan struct bnxt_vf_info *vf; 221c0c050c5SMichael Chan int rc; 222c0c050c5SMichael Chan 223c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 224c0c050c5SMichael Chan if (rc) 225c0c050c5SMichael Chan return rc; 226c0c050c5SMichael Chan /* reject bc or mc mac addr, zero mac addr means allow 227c0c050c5SMichael Chan * VF to use its own mac addr 228c0c050c5SMichael Chan */ 229c0c050c5SMichael Chan if (is_multicast_ether_addr(mac)) { 230c0c050c5SMichael Chan netdev_err(dev, "Invalid VF ethernet address\n"); 231c0c050c5SMichael Chan return -EINVAL; 232c0c050c5SMichael Chan } 233c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 234c0c050c5SMichael Chan 235bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 236bbf33d1dSEdwin Peer if (rc) 237bbf33d1dSEdwin Peer return rc; 238bbf33d1dSEdwin Peer 239c0c050c5SMichael Chan memcpy(vf->mac_addr, mac, ETH_ALEN); 240bbf33d1dSEdwin Peer 241bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 242bbf33d1dSEdwin Peer req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 243bbf33d1dSEdwin Peer memcpy(req->dflt_mac_addr, mac, ETH_ALEN); 244bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 245c0c050c5SMichael Chan } 246c0c050c5SMichael Chan 24779aab093SMoshe Shemesh int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos, 24879aab093SMoshe Shemesh __be16 vlan_proto) 249c0c050c5SMichael Chan { 250c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 251bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 252c0c050c5SMichael Chan struct bnxt_vf_info *vf; 253c0c050c5SMichael Chan u16 vlan_tag; 254c0c050c5SMichael Chan int rc; 255c0c050c5SMichael Chan 256cf6645f8SMichael Chan if (bp->hwrm_spec_code < 0x10201) 257cf6645f8SMichael Chan return -ENOTSUPP; 258cf6645f8SMichael Chan 25979aab093SMoshe Shemesh if (vlan_proto != htons(ETH_P_8021Q)) 26079aab093SMoshe Shemesh return -EPROTONOSUPPORT; 26179aab093SMoshe Shemesh 262c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 263c0c050c5SMichael Chan if (rc) 264c0c050c5SMichael Chan return rc; 265c0c050c5SMichael Chan 266c0c050c5SMichael Chan /* TODO: needed to implement proper handling of user priority, 267c0c050c5SMichael Chan * currently fail the command if there is valid priority 268c0c050c5SMichael Chan */ 269c0c050c5SMichael Chan if (vlan_id > 4095 || qos) 270c0c050c5SMichael Chan return -EINVAL; 271c0c050c5SMichael Chan 272c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 273c0c050c5SMichael Chan vlan_tag = vlan_id; 274c0c050c5SMichael Chan if (vlan_tag == vf->vlan) 275c0c050c5SMichael Chan return 0; 276c0c050c5SMichael Chan 277bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 278bbf33d1dSEdwin Peer if (!rc) { 279bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 280bbf33d1dSEdwin Peer req->dflt_vlan = cpu_to_le16(vlan_tag); 281bbf33d1dSEdwin Peer req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN); 282bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 283c0c050c5SMichael Chan if (!rc) 284c0c050c5SMichael Chan vf->vlan = vlan_tag; 285bbf33d1dSEdwin Peer } 286c0c050c5SMichael Chan return rc; 287c0c050c5SMichael Chan } 288c0c050c5SMichael Chan 289c0c050c5SMichael Chan int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate, 290c0c050c5SMichael Chan int max_tx_rate) 291c0c050c5SMichael Chan { 292c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 293bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 294c0c050c5SMichael Chan struct bnxt_vf_info *vf; 295c0c050c5SMichael Chan u32 pf_link_speed; 296c0c050c5SMichael Chan int rc; 297c0c050c5SMichael Chan 298c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 299c0c050c5SMichael Chan if (rc) 300c0c050c5SMichael Chan return rc; 301c0c050c5SMichael Chan 302c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 303c0c050c5SMichael Chan pf_link_speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed); 304c0c050c5SMichael Chan if (max_tx_rate > pf_link_speed) { 305c0c050c5SMichael Chan netdev_info(bp->dev, "max tx rate %d exceed PF link speed for VF %d\n", 306c0c050c5SMichael Chan max_tx_rate, vf_id); 307c0c050c5SMichael Chan return -EINVAL; 308c0c050c5SMichael Chan } 309c0c050c5SMichael Chan 31010e11aa2SBin Chen if (min_tx_rate > pf_link_speed) { 311c0c050c5SMichael Chan netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n", 312c0c050c5SMichael Chan min_tx_rate, vf_id); 313c0c050c5SMichael Chan return -EINVAL; 314c0c050c5SMichael Chan } 315c0c050c5SMichael Chan if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate) 316c0c050c5SMichael Chan return 0; 317bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 318bbf33d1dSEdwin Peer if (!rc) { 319bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 320bbf33d1dSEdwin Peer req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW | 321bbf33d1dSEdwin Peer FUNC_CFG_REQ_ENABLES_MIN_BW); 322bbf33d1dSEdwin Peer req->max_bw = cpu_to_le32(max_tx_rate); 323bbf33d1dSEdwin Peer req->min_bw = cpu_to_le32(min_tx_rate); 324bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 325c0c050c5SMichael Chan if (!rc) { 326c0c050c5SMichael Chan vf->min_tx_rate = min_tx_rate; 327c0c050c5SMichael Chan vf->max_tx_rate = max_tx_rate; 328c0c050c5SMichael Chan } 329bbf33d1dSEdwin Peer } 330c0c050c5SMichael Chan return rc; 331c0c050c5SMichael Chan } 332c0c050c5SMichael Chan 333c0c050c5SMichael Chan int bnxt_set_vf_link_state(struct net_device *dev, int vf_id, int link) 334c0c050c5SMichael Chan { 335c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 336c0c050c5SMichael Chan struct bnxt_vf_info *vf; 337c0c050c5SMichael Chan int rc; 338c0c050c5SMichael Chan 339c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 340c0c050c5SMichael Chan if (rc) 341c0c050c5SMichael Chan return rc; 342c0c050c5SMichael Chan 343c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 344c0c050c5SMichael Chan 345c0c050c5SMichael Chan vf->flags &= ~(BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED); 346c0c050c5SMichael Chan switch (link) { 347c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_AUTO: 348c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_UP; 349c0c050c5SMichael Chan break; 350c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_DISABLE: 351c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_FORCED; 352c0c050c5SMichael Chan break; 353c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_ENABLE: 354c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED; 355c0c050c5SMichael Chan break; 356c0c050c5SMichael Chan default: 357c0c050c5SMichael Chan netdev_err(bp->dev, "Invalid link option\n"); 358c0c050c5SMichael Chan rc = -EINVAL; 359c0c050c5SMichael Chan break; 360c0c050c5SMichael Chan } 361350a7149SEddie Wai if (vf->flags & (BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED)) 362350a7149SEddie Wai rc = bnxt_hwrm_fwd_async_event_cmpl(bp, vf, 36387c374deSMichael Chan ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE); 364c0c050c5SMichael Chan return rc; 365c0c050c5SMichael Chan } 366c0c050c5SMichael Chan 367c0c050c5SMichael Chan static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs) 368c0c050c5SMichael Chan { 369c0c050c5SMichael Chan int i; 370c0c050c5SMichael Chan struct bnxt_vf_info *vf; 371c0c050c5SMichael Chan 372c0c050c5SMichael Chan for (i = 0; i < num_vfs; i++) { 373c0c050c5SMichael Chan vf = &bp->pf.vf[i]; 374c0c050c5SMichael Chan memset(vf, 0, sizeof(*vf)); 375c0c050c5SMichael Chan } 376c0c050c5SMichael Chan return 0; 377c0c050c5SMichael Chan } 378c0c050c5SMichael Chan 3794bb6cdceSJeffrey Huang static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs) 380c0c050c5SMichael Chan { 381bbf33d1dSEdwin Peer struct hwrm_func_vf_resc_free_input *req; 382c0c050c5SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 383bbf33d1dSEdwin Peer int i, rc; 384c0c050c5SMichael Chan 385bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_RESC_FREE); 386bbf33d1dSEdwin Peer if (rc) 387bbf33d1dSEdwin Peer return rc; 388c0c050c5SMichael Chan 389bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 3904bb6cdceSJeffrey Huang for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) { 391bbf33d1dSEdwin Peer req->vf_id = cpu_to_le16(i); 392bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 393c0c050c5SMichael Chan if (rc) 394c0c050c5SMichael Chan break; 395c0c050c5SMichael Chan } 396bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 397c0c050c5SMichael Chan return rc; 398c0c050c5SMichael Chan } 399c0c050c5SMichael Chan 400c0c050c5SMichael Chan static void bnxt_free_vf_resources(struct bnxt *bp) 401c0c050c5SMichael Chan { 402c0c050c5SMichael Chan struct pci_dev *pdev = bp->pdev; 403c0c050c5SMichael Chan int i; 404c0c050c5SMichael Chan 405c0c050c5SMichael Chan kfree(bp->pf.vf_event_bmap); 406c0c050c5SMichael Chan bp->pf.vf_event_bmap = NULL; 407c0c050c5SMichael Chan 408c0c050c5SMichael Chan for (i = 0; i < 4; i++) { 409c0c050c5SMichael Chan if (bp->pf.hwrm_cmd_req_addr[i]) { 410c0c050c5SMichael Chan dma_free_coherent(&pdev->dev, BNXT_PAGE_SIZE, 411c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i], 412c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_dma_addr[i]); 413c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i] = NULL; 414c0c050c5SMichael Chan } 415c0c050c5SMichael Chan } 416c0c050c5SMichael Chan 417c8b1d743SDavide Caratti bp->pf.active_vfs = 0; 418c0c050c5SMichael Chan kfree(bp->pf.vf); 419c0c050c5SMichael Chan bp->pf.vf = NULL; 420c0c050c5SMichael Chan } 421c0c050c5SMichael Chan 422c0c050c5SMichael Chan static int bnxt_alloc_vf_resources(struct bnxt *bp, int num_vfs) 423c0c050c5SMichael Chan { 424c0c050c5SMichael Chan struct pci_dev *pdev = bp->pdev; 425c0c050c5SMichael Chan u32 nr_pages, size, i, j, k = 0; 426c0c050c5SMichael Chan 427c0c050c5SMichael Chan bp->pf.vf = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL); 428c0c050c5SMichael Chan if (!bp->pf.vf) 429c0c050c5SMichael Chan return -ENOMEM; 430c0c050c5SMichael Chan 431c0c050c5SMichael Chan bnxt_set_vf_attr(bp, num_vfs); 432c0c050c5SMichael Chan 433c0c050c5SMichael Chan size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE; 434c0c050c5SMichael Chan nr_pages = size / BNXT_PAGE_SIZE; 435c0c050c5SMichael Chan if (size & (BNXT_PAGE_SIZE - 1)) 436c0c050c5SMichael Chan nr_pages++; 437c0c050c5SMichael Chan 438c0c050c5SMichael Chan for (i = 0; i < nr_pages; i++) { 439c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i] = 440c0c050c5SMichael Chan dma_alloc_coherent(&pdev->dev, BNXT_PAGE_SIZE, 441c0c050c5SMichael Chan &bp->pf.hwrm_cmd_req_dma_addr[i], 442c0c050c5SMichael Chan GFP_KERNEL); 443c0c050c5SMichael Chan 444c0c050c5SMichael Chan if (!bp->pf.hwrm_cmd_req_addr[i]) 445c0c050c5SMichael Chan return -ENOMEM; 446c0c050c5SMichael Chan 447c0c050c5SMichael Chan for (j = 0; j < BNXT_HWRM_REQS_PER_PAGE && k < num_vfs; j++) { 448c0c050c5SMichael Chan struct bnxt_vf_info *vf = &bp->pf.vf[k]; 449c0c050c5SMichael Chan 450c0c050c5SMichael Chan vf->hwrm_cmd_req_addr = bp->pf.hwrm_cmd_req_addr[i] + 451c0c050c5SMichael Chan j * BNXT_HWRM_REQ_MAX_SIZE; 452c0c050c5SMichael Chan vf->hwrm_cmd_req_dma_addr = 453c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_dma_addr[i] + j * 454c0c050c5SMichael Chan BNXT_HWRM_REQ_MAX_SIZE; 455c0c050c5SMichael Chan k++; 456c0c050c5SMichael Chan } 457c0c050c5SMichael Chan } 458c0c050c5SMichael Chan 459c0c050c5SMichael Chan /* Max 128 VF's */ 460c0c050c5SMichael Chan bp->pf.vf_event_bmap = kzalloc(16, GFP_KERNEL); 461c0c050c5SMichael Chan if (!bp->pf.vf_event_bmap) 462c0c050c5SMichael Chan return -ENOMEM; 463c0c050c5SMichael Chan 464c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_pages = nr_pages; 465c0c050c5SMichael Chan return 0; 466c0c050c5SMichael Chan } 467c0c050c5SMichael Chan 468c0c050c5SMichael Chan static int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp) 469c0c050c5SMichael Chan { 470bbf33d1dSEdwin Peer struct hwrm_func_buf_rgtr_input *req; 471bbf33d1dSEdwin Peer int rc; 472c0c050c5SMichael Chan 473bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_BUF_RGTR); 474bbf33d1dSEdwin Peer if (rc) 475bbf33d1dSEdwin Peer return rc; 476c0c050c5SMichael Chan 477bbf33d1dSEdwin Peer req->req_buf_num_pages = cpu_to_le16(bp->pf.hwrm_cmd_req_pages); 478bbf33d1dSEdwin Peer req->req_buf_page_size = cpu_to_le16(BNXT_PAGE_SHIFT); 479bbf33d1dSEdwin Peer req->req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE); 480bbf33d1dSEdwin Peer req->req_buf_page_addr0 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[0]); 481bbf33d1dSEdwin Peer req->req_buf_page_addr1 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[1]); 482bbf33d1dSEdwin Peer req->req_buf_page_addr2 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[2]); 483bbf33d1dSEdwin Peer req->req_buf_page_addr3 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[3]); 484c0c050c5SMichael Chan 485bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 486c0c050c5SMichael Chan } 487c0c050c5SMichael Chan 488bbf33d1dSEdwin Peer static int __bnxt_set_vf_params(struct bnxt *bp, int vf_id) 4892cd86968SVasundhara Volam { 490bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 4912cd86968SVasundhara Volam struct bnxt_vf_info *vf; 492bbf33d1dSEdwin Peer int rc; 493bbf33d1dSEdwin Peer 494bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 495bbf33d1dSEdwin Peer if (rc) 496bbf33d1dSEdwin Peer return rc; 4972cd86968SVasundhara Volam 4982cd86968SVasundhara Volam vf = &bp->pf.vf[vf_id]; 499bbf33d1dSEdwin Peer req->fid = cpu_to_le16(vf->fw_fid); 5002cd86968SVasundhara Volam 5012cd86968SVasundhara Volam if (is_valid_ether_addr(vf->mac_addr)) { 502bbf33d1dSEdwin Peer req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 503bbf33d1dSEdwin Peer memcpy(req->dflt_mac_addr, vf->mac_addr, ETH_ALEN); 5042cd86968SVasundhara Volam } 5052cd86968SVasundhara Volam if (vf->vlan) { 506bbf33d1dSEdwin Peer req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN); 507bbf33d1dSEdwin Peer req->dflt_vlan = cpu_to_le16(vf->vlan); 5082cd86968SVasundhara Volam } 5092cd86968SVasundhara Volam if (vf->max_tx_rate) { 510bbf33d1dSEdwin Peer req->enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW | 511bbf33d1dSEdwin Peer FUNC_CFG_REQ_ENABLES_MIN_BW); 512bbf33d1dSEdwin Peer req->max_bw = cpu_to_le32(vf->max_tx_rate); 513bbf33d1dSEdwin Peer req->min_bw = cpu_to_le32(vf->min_tx_rate); 5142cd86968SVasundhara Volam } 5152cd86968SVasundhara Volam if (vf->flags & BNXT_VF_TRUST) 516bbf33d1dSEdwin Peer req->flags |= cpu_to_le32(FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE); 5172cd86968SVasundhara Volam 518bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 5192cd86968SVasundhara Volam } 5202cd86968SVasundhara Volam 5214673d664SMichael Chan /* Only called by PF to reserve resources for VFs, returns actual number of 5224673d664SMichael Chan * VFs configured, or < 0 on error. 5234673d664SMichael Chan */ 5242cd86968SVasundhara Volam static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) 5254673d664SMichael Chan { 526bbf33d1dSEdwin Peer struct hwrm_func_vf_resource_cfg_input *req; 5274673d664SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 5284673d664SMichael Chan u16 vf_tx_rings, vf_rx_rings, vf_cp_rings; 5294673d664SMichael Chan u16 vf_stat_ctx, vf_vnics, vf_ring_grps; 5304673d664SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 531bf82736dSMichael Chan int i, rc = 0, min = 1; 532b16b6891SMichael Chan u16 vf_msix = 0; 5331acefc9aSMichael Chan u16 vf_rss; 5344673d664SMichael Chan 535bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_RESOURCE_CFG); 536bbf33d1dSEdwin Peer if (rc) 537bbf33d1dSEdwin Peer return rc; 5384673d664SMichael Chan 539b16b6891SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) { 540b16b6891SMichael Chan vf_msix = hw_resc->max_nqs - bnxt_nq_rings_in_use(bp); 541b16b6891SMichael Chan vf_ring_grps = 0; 542b16b6891SMichael Chan } else { 543b16b6891SMichael Chan vf_ring_grps = hw_resc->max_hw_ring_grps - bp->rx_nr_rings; 544b16b6891SMichael Chan } 545e916b081SMichael Chan vf_cp_rings = bnxt_get_avail_cp_rings_for_en(bp); 546c027c6b4SVasundhara Volam vf_stat_ctx = bnxt_get_avail_stat_ctxs_for_en(bp); 5474673d664SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) 5484673d664SMichael Chan vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings * 2; 5494673d664SMichael Chan else 5504673d664SMichael Chan vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings; 5514673d664SMichael Chan vf_tx_rings = hw_resc->max_tx_rings - bp->tx_nr_rings; 5524673d664SMichael Chan vf_vnics = hw_resc->max_vnics - bp->nr_vnics; 5534673d664SMichael Chan vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 5541acefc9aSMichael Chan vf_rss = hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs; 5554673d664SMichael Chan 556bbf33d1dSEdwin Peer req->min_rsscos_ctx = cpu_to_le16(BNXT_VF_MIN_RSS_CTX); 557bf82736dSMichael Chan if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL_STATIC) { 558bf82736dSMichael Chan min = 0; 559bbf33d1dSEdwin Peer req->min_rsscos_ctx = cpu_to_le16(min); 560bf82736dSMichael Chan } 561bf82736dSMichael Chan if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL || 562bf82736dSMichael Chan pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL_STATIC) { 563bbf33d1dSEdwin Peer req->min_cmpl_rings = cpu_to_le16(min); 564bbf33d1dSEdwin Peer req->min_tx_rings = cpu_to_le16(min); 565bbf33d1dSEdwin Peer req->min_rx_rings = cpu_to_le16(min); 566bbf33d1dSEdwin Peer req->min_l2_ctxs = cpu_to_le16(min); 567bbf33d1dSEdwin Peer req->min_vnics = cpu_to_le16(min); 568bbf33d1dSEdwin Peer req->min_stat_ctx = cpu_to_le16(min); 569b16b6891SMichael Chan if (!(bp->flags & BNXT_FLAG_CHIP_P5)) 570bbf33d1dSEdwin Peer req->min_hw_ring_grps = cpu_to_le16(min); 5714673d664SMichael Chan } else { 5724673d664SMichael Chan vf_cp_rings /= num_vfs; 5734673d664SMichael Chan vf_tx_rings /= num_vfs; 5744673d664SMichael Chan vf_rx_rings /= num_vfs; 5754673d664SMichael Chan vf_vnics /= num_vfs; 5764673d664SMichael Chan vf_stat_ctx /= num_vfs; 5774673d664SMichael Chan vf_ring_grps /= num_vfs; 5781acefc9aSMichael Chan vf_rss /= num_vfs; 5794673d664SMichael Chan 580bbf33d1dSEdwin Peer req->min_cmpl_rings = cpu_to_le16(vf_cp_rings); 581bbf33d1dSEdwin Peer req->min_tx_rings = cpu_to_le16(vf_tx_rings); 582bbf33d1dSEdwin Peer req->min_rx_rings = cpu_to_le16(vf_rx_rings); 583bbf33d1dSEdwin Peer req->min_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); 584bbf33d1dSEdwin Peer req->min_vnics = cpu_to_le16(vf_vnics); 585bbf33d1dSEdwin Peer req->min_stat_ctx = cpu_to_le16(vf_stat_ctx); 586bbf33d1dSEdwin Peer req->min_hw_ring_grps = cpu_to_le16(vf_ring_grps); 587bbf33d1dSEdwin Peer req->min_rsscos_ctx = cpu_to_le16(vf_rss); 5884673d664SMichael Chan } 589bbf33d1dSEdwin Peer req->max_cmpl_rings = cpu_to_le16(vf_cp_rings); 590bbf33d1dSEdwin Peer req->max_tx_rings = cpu_to_le16(vf_tx_rings); 591bbf33d1dSEdwin Peer req->max_rx_rings = cpu_to_le16(vf_rx_rings); 592bbf33d1dSEdwin Peer req->max_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); 593bbf33d1dSEdwin Peer req->max_vnics = cpu_to_le16(vf_vnics); 594bbf33d1dSEdwin Peer req->max_stat_ctx = cpu_to_le16(vf_stat_ctx); 595bbf33d1dSEdwin Peer req->max_hw_ring_grps = cpu_to_le16(vf_ring_grps); 596bbf33d1dSEdwin Peer req->max_rsscos_ctx = cpu_to_le16(vf_rss); 597b16b6891SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 598bbf33d1dSEdwin Peer req->max_msix = cpu_to_le16(vf_msix / num_vfs); 5994673d664SMichael Chan 600bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 6014673d664SMichael Chan for (i = 0; i < num_vfs; i++) { 6022cd86968SVasundhara Volam if (reset) 6032cd86968SVasundhara Volam __bnxt_set_vf_params(bp, i); 6042cd86968SVasundhara Volam 605bbf33d1dSEdwin Peer req->vf_id = cpu_to_le16(pf->first_vf_id + i); 606bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 607d4f1420dSMichael Chan if (rc) 6084673d664SMichael Chan break; 6094673d664SMichael Chan pf->active_vfs = i + 1; 6104673d664SMichael Chan pf->vf[i].fw_fid = pf->first_vf_id + i; 6114673d664SMichael Chan } 612bbf33d1dSEdwin Peer 6134673d664SMichael Chan if (pf->active_vfs) { 614596f9d55SMichael Chan u16 n = pf->active_vfs; 6154673d664SMichael Chan 616bbf33d1dSEdwin Peer hw_resc->max_tx_rings -= le16_to_cpu(req->min_tx_rings) * n; 617bbf33d1dSEdwin Peer hw_resc->max_rx_rings -= le16_to_cpu(req->min_rx_rings) * n; 618bbf33d1dSEdwin Peer hw_resc->max_hw_ring_grps -= 619bbf33d1dSEdwin Peer le16_to_cpu(req->min_hw_ring_grps) * n; 620bbf33d1dSEdwin Peer hw_resc->max_cp_rings -= le16_to_cpu(req->min_cmpl_rings) * n; 621bbf33d1dSEdwin Peer hw_resc->max_rsscos_ctxs -= 622bbf33d1dSEdwin Peer le16_to_cpu(req->min_rsscos_ctx) * n; 623bbf33d1dSEdwin Peer hw_resc->max_stat_ctxs -= le16_to_cpu(req->min_stat_ctx) * n; 624bbf33d1dSEdwin Peer hw_resc->max_vnics -= le16_to_cpu(req->min_vnics) * n; 625b16b6891SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 626*09a89cc5SVikas Gupta hw_resc->max_nqs -= vf_msix; 6274673d664SMichael Chan 6284673d664SMichael Chan rc = pf->active_vfs; 6294673d664SMichael Chan } 630bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 6314673d664SMichael Chan return rc; 6324673d664SMichael Chan } 6334673d664SMichael Chan 6344673d664SMichael Chan /* Only called by PF to reserve resources for VFs, returns actual number of 6354673d664SMichael Chan * VFs configured, or < 0 on error. 6364673d664SMichael Chan */ 63792268c32SMichael Chan static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs) 638c0c050c5SMichael Chan { 639c0c050c5SMichael Chan u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics; 6406a4f2947SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 641c0c050c5SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 642bbf33d1dSEdwin Peer struct hwrm_func_cfg_input *req; 643391be5c2SMichael Chan int total_vf_tx_rings = 0; 644c027c6b4SVasundhara Volam u16 vf_ring_grps; 645bbf33d1dSEdwin Peer u32 mtu, i; 646bbf33d1dSEdwin Peer int rc; 647c0c050c5SMichael Chan 648bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); 649bbf33d1dSEdwin Peer if (rc) 650bbf33d1dSEdwin Peer return rc; 651c0c050c5SMichael Chan 652c0c050c5SMichael Chan /* Remaining rings are distributed equally amongs VF's for now */ 653e916b081SMichael Chan vf_cp_rings = bnxt_get_avail_cp_rings_for_en(bp) / num_vfs; 654c027c6b4SVasundhara Volam vf_stat_ctx = bnxt_get_avail_stat_ctxs_for_en(bp) / num_vfs; 655c0c050c5SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) 6566a4f2947SMichael Chan vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings * 2) / 65792268c32SMichael Chan num_vfs; 658c0c050c5SMichael Chan else 6596a4f2947SMichael Chan vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings) / 6606a4f2947SMichael Chan num_vfs; 6616a4f2947SMichael Chan vf_ring_grps = (hw_resc->max_hw_ring_grps - bp->rx_nr_rings) / num_vfs; 6626a4f2947SMichael Chan vf_tx_rings = (hw_resc->max_tx_rings - bp->tx_nr_rings) / num_vfs; 6636a4f2947SMichael Chan vf_vnics = (hw_resc->max_vnics - bp->nr_vnics) / num_vfs; 6648427af81SMichael Chan vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 665c0c050c5SMichael Chan 666bbf33d1dSEdwin Peer req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_ADMIN_MTU | 667c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_MRU | 668c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS | 669c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS | 670c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | 671c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS | 672c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS | 673c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_L2_CTXS | 674b72d4a68SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_VNICS | 675b72d4a68SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS); 676c0c050c5SMichael Chan 677d0b82c54SVasundhara Volam mtu = bp->dev->mtu + ETH_HLEN + VLAN_HLEN; 678bbf33d1dSEdwin Peer req->mru = cpu_to_le16(mtu); 679bbf33d1dSEdwin Peer req->admin_mtu = cpu_to_le16(mtu); 680c0c050c5SMichael Chan 681bbf33d1dSEdwin Peer req->num_rsscos_ctxs = cpu_to_le16(1); 682bbf33d1dSEdwin Peer req->num_cmpl_rings = cpu_to_le16(vf_cp_rings); 683bbf33d1dSEdwin Peer req->num_tx_rings = cpu_to_le16(vf_tx_rings); 684bbf33d1dSEdwin Peer req->num_rx_rings = cpu_to_le16(vf_rx_rings); 685bbf33d1dSEdwin Peer req->num_hw_ring_grps = cpu_to_le16(vf_ring_grps); 686bbf33d1dSEdwin Peer req->num_l2_ctxs = cpu_to_le16(4); 687c0c050c5SMichael Chan 688bbf33d1dSEdwin Peer req->num_vnics = cpu_to_le16(vf_vnics); 689c0c050c5SMichael Chan /* FIXME spec currently uses 1 bit for stats ctx */ 690bbf33d1dSEdwin Peer req->num_stat_ctxs = cpu_to_le16(vf_stat_ctx); 691c0c050c5SMichael Chan 692bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 69392268c32SMichael Chan for (i = 0; i < num_vfs; i++) { 694391be5c2SMichael Chan int vf_tx_rsvd = vf_tx_rings; 695391be5c2SMichael Chan 696bbf33d1dSEdwin Peer req->fid = cpu_to_le16(pf->first_vf_id + i); 697bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 698c0c050c5SMichael Chan if (rc) 699c0c050c5SMichael Chan break; 70092268c32SMichael Chan pf->active_vfs = i + 1; 701bbf33d1dSEdwin Peer pf->vf[i].fw_fid = le16_to_cpu(req->fid); 702391be5c2SMichael Chan rc = __bnxt_hwrm_get_tx_rings(bp, pf->vf[i].fw_fid, 703391be5c2SMichael Chan &vf_tx_rsvd); 704391be5c2SMichael Chan if (rc) 705391be5c2SMichael Chan break; 706391be5c2SMichael Chan total_vf_tx_rings += vf_tx_rsvd; 707c0c050c5SMichael Chan } 708bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 7094673d664SMichael Chan if (pf->active_vfs) { 7106a4f2947SMichael Chan hw_resc->max_tx_rings -= total_vf_tx_rings; 7116a4f2947SMichael Chan hw_resc->max_rx_rings -= vf_rx_rings * num_vfs; 7126a4f2947SMichael Chan hw_resc->max_hw_ring_grps -= vf_ring_grps * num_vfs; 7136a4f2947SMichael Chan hw_resc->max_cp_rings -= vf_cp_rings * num_vfs; 7146a4f2947SMichael Chan hw_resc->max_rsscos_ctxs -= num_vfs; 7156a4f2947SMichael Chan hw_resc->max_stat_ctxs -= vf_stat_ctx * num_vfs; 7166a4f2947SMichael Chan hw_resc->max_vnics -= vf_vnics * num_vfs; 7174673d664SMichael Chan rc = pf->active_vfs; 718c0c050c5SMichael Chan } 719c0c050c5SMichael Chan return rc; 720c0c050c5SMichael Chan } 721c0c050c5SMichael Chan 7222cd86968SVasundhara Volam static int bnxt_func_cfg(struct bnxt *bp, int num_vfs, bool reset) 7234673d664SMichael Chan { 724f1ca94deSMichael Chan if (BNXT_NEW_RM(bp)) 7252cd86968SVasundhara Volam return bnxt_hwrm_func_vf_resc_cfg(bp, num_vfs, reset); 7264673d664SMichael Chan else 7274673d664SMichael Chan return bnxt_hwrm_func_cfg(bp, num_vfs); 7284673d664SMichael Chan } 7294673d664SMichael Chan 7302cd86968SVasundhara Volam int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) 731702d5011SMichael Chan { 732702d5011SMichael Chan int rc; 733702d5011SMichael Chan 73491b9be48SVasundhara Volam /* Register buffers for VFs */ 73591b9be48SVasundhara Volam rc = bnxt_hwrm_func_buf_rgtr(bp); 73691b9be48SVasundhara Volam if (rc) 73791b9be48SVasundhara Volam return rc; 73891b9be48SVasundhara Volam 739702d5011SMichael Chan /* Reserve resources for VFs */ 7402cd86968SVasundhara Volam rc = bnxt_func_cfg(bp, *num_vfs, reset); 741702d5011SMichael Chan if (rc != *num_vfs) { 742702d5011SMichael Chan if (rc <= 0) { 743702d5011SMichael Chan netdev_warn(bp->dev, "Unable to reserve resources for SRIOV.\n"); 744702d5011SMichael Chan *num_vfs = 0; 745702d5011SMichael Chan return rc; 746702d5011SMichael Chan } 747702d5011SMichael Chan netdev_warn(bp->dev, "Only able to reserve resources for %d VFs.\n", 748702d5011SMichael Chan rc); 749702d5011SMichael Chan *num_vfs = rc; 750702d5011SMichael Chan } 751702d5011SMichael Chan 752702d5011SMichael Chan bnxt_ulp_sriov_cfg(bp, *num_vfs); 753702d5011SMichael Chan return 0; 754702d5011SMichael Chan } 755702d5011SMichael Chan 756c0c050c5SMichael Chan static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs) 757c0c050c5SMichael Chan { 758c0c050c5SMichael Chan int rc = 0, vfs_supported; 759c0c050c5SMichael Chan int min_rx_rings, min_tx_rings, min_rss_ctxs; 7606a4f2947SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 761c0c050c5SMichael Chan int tx_ok = 0, rx_ok = 0, rss_ok = 0; 76202157079SMichael Chan int avail_cp, avail_stat; 763c0c050c5SMichael Chan 764c0c050c5SMichael Chan /* Check if we can enable requested num of vf's. At a mininum 765c0c050c5SMichael Chan * we require 1 RX 1 TX rings for each VF. In this minimum conf 766c0c050c5SMichael Chan * features like TPA will not be available. 767c0c050c5SMichael Chan */ 768c0c050c5SMichael Chan vfs_supported = *num_vfs; 769c0c050c5SMichael Chan 770e916b081SMichael Chan avail_cp = bnxt_get_avail_cp_rings_for_en(bp); 771c027c6b4SVasundhara Volam avail_stat = bnxt_get_avail_stat_ctxs_for_en(bp); 77202157079SMichael Chan avail_cp = min_t(int, avail_cp, avail_stat); 77302157079SMichael Chan 774c0c050c5SMichael Chan while (vfs_supported) { 775c0c050c5SMichael Chan min_rx_rings = vfs_supported; 776c0c050c5SMichael Chan min_tx_rings = vfs_supported; 777c0c050c5SMichael Chan min_rss_ctxs = vfs_supported; 778c0c050c5SMichael Chan 779c0c050c5SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) { 7806a4f2947SMichael Chan if (hw_resc->max_rx_rings - bp->rx_nr_rings * 2 >= 781c0c050c5SMichael Chan min_rx_rings) 782c0c050c5SMichael Chan rx_ok = 1; 783c0c050c5SMichael Chan } else { 7846a4f2947SMichael Chan if (hw_resc->max_rx_rings - bp->rx_nr_rings >= 785c0c050c5SMichael Chan min_rx_rings) 786c0c050c5SMichael Chan rx_ok = 1; 787c0c050c5SMichael Chan } 7886a4f2947SMichael Chan if (hw_resc->max_vnics - bp->nr_vnics < min_rx_rings || 78902157079SMichael Chan avail_cp < min_rx_rings) 7908427af81SMichael Chan rx_ok = 0; 791c0c050c5SMichael Chan 7926a4f2947SMichael Chan if (hw_resc->max_tx_rings - bp->tx_nr_rings >= min_tx_rings && 79302157079SMichael Chan avail_cp >= min_tx_rings) 794c0c050c5SMichael Chan tx_ok = 1; 795c0c050c5SMichael Chan 7966a4f2947SMichael Chan if (hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs >= 7976a4f2947SMichael Chan min_rss_ctxs) 798c0c050c5SMichael Chan rss_ok = 1; 799c0c050c5SMichael Chan 800c0c050c5SMichael Chan if (tx_ok && rx_ok && rss_ok) 801c0c050c5SMichael Chan break; 802c0c050c5SMichael Chan 803c0c050c5SMichael Chan vfs_supported--; 804c0c050c5SMichael Chan } 805c0c050c5SMichael Chan 806c0c050c5SMichael Chan if (!vfs_supported) { 807c0c050c5SMichael Chan netdev_err(bp->dev, "Cannot enable VF's as all resources are used by PF\n"); 808c0c050c5SMichael Chan return -EINVAL; 809c0c050c5SMichael Chan } 810c0c050c5SMichael Chan 811c0c050c5SMichael Chan if (vfs_supported != *num_vfs) { 812c0c050c5SMichael Chan netdev_info(bp->dev, "Requested VFs %d, can enable %d\n", 813c0c050c5SMichael Chan *num_vfs, vfs_supported); 814c0c050c5SMichael Chan *num_vfs = vfs_supported; 815c0c050c5SMichael Chan } 816c0c050c5SMichael Chan 817c0c050c5SMichael Chan rc = bnxt_alloc_vf_resources(bp, *num_vfs); 818c0c050c5SMichael Chan if (rc) 819c0c050c5SMichael Chan goto err_out1; 820c0c050c5SMichael Chan 8212cd86968SVasundhara Volam rc = bnxt_cfg_hw_sriov(bp, num_vfs, false); 822c0c050c5SMichael Chan if (rc) 823c0c050c5SMichael Chan goto err_out2; 824c0c050c5SMichael Chan 825c0c050c5SMichael Chan rc = pci_enable_sriov(bp->pdev, *num_vfs); 826c5b744d3SKashyap Desai if (rc) { 827c5b744d3SKashyap Desai bnxt_ulp_sriov_cfg(bp, 0); 828c0c050c5SMichael Chan goto err_out2; 829c5b744d3SKashyap Desai } 830c0c050c5SMichael Chan 831c0c050c5SMichael Chan return 0; 832c0c050c5SMichael Chan 833c0c050c5SMichael Chan err_out2: 834c0c050c5SMichael Chan /* Free the resources reserved for various VF's */ 8354bb6cdceSJeffrey Huang bnxt_hwrm_func_vf_resource_free(bp, *num_vfs); 836c0c050c5SMichael Chan 837c5b744d3SKashyap Desai /* Restore the max resources */ 838c5b744d3SKashyap Desai bnxt_hwrm_func_qcaps(bp); 839c5b744d3SKashyap Desai 840c0c050c5SMichael Chan err_out1: 841c0c050c5SMichael Chan bnxt_free_vf_resources(bp); 842c0c050c5SMichael Chan 843c0c050c5SMichael Chan return rc; 844c0c050c5SMichael Chan } 845c0c050c5SMichael Chan 846c0c050c5SMichael Chan void bnxt_sriov_disable(struct bnxt *bp) 847c0c050c5SMichael Chan { 8484bb6cdceSJeffrey Huang u16 num_vfs = pci_num_vf(bp->pdev); 8494bb6cdceSJeffrey Huang 8504bb6cdceSJeffrey Huang if (!num_vfs) 851c0c050c5SMichael Chan return; 852c0c050c5SMichael Chan 8534ab0c6a8SSathya Perla /* synchronize VF and VF-rep create and destroy */ 8547a1b0b1aSJakub Kicinski devl_lock(bp->dl); 8554ab0c6a8SSathya Perla bnxt_vf_reps_destroy(bp); 8564ab0c6a8SSathya Perla 8574bb6cdceSJeffrey Huang if (pci_vfs_assigned(bp->pdev)) { 85819241368SJeffrey Huang bnxt_hwrm_fwd_async_event_cmpl( 85987c374deSMichael Chan bp, NULL, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD); 8604bb6cdceSJeffrey Huang netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n", 8614bb6cdceSJeffrey Huang num_vfs); 8624bb6cdceSJeffrey Huang } else { 863c0c050c5SMichael Chan pci_disable_sriov(bp->pdev); 8644bb6cdceSJeffrey Huang /* Free the HW resources reserved for various VF's */ 8654bb6cdceSJeffrey Huang bnxt_hwrm_func_vf_resource_free(bp, num_vfs); 8664bb6cdceSJeffrey Huang } 8677a1b0b1aSJakub Kicinski devl_unlock(bp->dl); 868c0c050c5SMichael Chan 869c0c050c5SMichael Chan bnxt_free_vf_resources(bp); 870c0c050c5SMichael Chan 8714a21b49bSMichael Chan /* Reclaim all resources for the PF. */ 8727b08f661SMichael Chan rtnl_lock(); 8737b08f661SMichael Chan bnxt_restore_pf_fw_resources(bp); 8747b08f661SMichael Chan rtnl_unlock(); 8752f593846SMichael Chan 8762f593846SMichael Chan bnxt_ulp_sriov_cfg(bp, 0); 877c0c050c5SMichael Chan } 878c0c050c5SMichael Chan 879c0c050c5SMichael Chan int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs) 880c0c050c5SMichael Chan { 881c0c050c5SMichael Chan struct net_device *dev = pci_get_drvdata(pdev); 882c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 883c0c050c5SMichael Chan 884c0c050c5SMichael Chan if (!(bp->flags & BNXT_FLAG_USING_MSIX)) { 885c0c050c5SMichael Chan netdev_warn(dev, "Not allow SRIOV if the irq mode is not MSIX\n"); 886c0c050c5SMichael Chan return 0; 887c0c050c5SMichael Chan } 888c0c050c5SMichael Chan 889c0c050c5SMichael Chan rtnl_lock(); 890c0c050c5SMichael Chan if (!netif_running(dev)) { 891c0c050c5SMichael Chan netdev_warn(dev, "Reject SRIOV config request since if is down!\n"); 892c0c050c5SMichael Chan rtnl_unlock(); 893c0c050c5SMichael Chan return 0; 894c0c050c5SMichael Chan } 8953bc7d4a3SMichael Chan if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { 8963bc7d4a3SMichael Chan netdev_warn(dev, "Reject SRIOV config request when FW reset is in progress\n"); 8973bc7d4a3SMichael Chan rtnl_unlock(); 8983bc7d4a3SMichael Chan return 0; 8993bc7d4a3SMichael Chan } 900c0c050c5SMichael Chan bp->sriov_cfg = true; 901c0c050c5SMichael Chan rtnl_unlock(); 9024bb6cdceSJeffrey Huang 9034bb6cdceSJeffrey Huang if (pci_vfs_assigned(bp->pdev)) { 9044bb6cdceSJeffrey Huang netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n"); 9054bb6cdceSJeffrey Huang num_vfs = 0; 9064bb6cdceSJeffrey Huang goto sriov_cfg_exit; 907c0c050c5SMichael Chan } 908c0c050c5SMichael Chan 909c0c050c5SMichael Chan /* Check if enabled VFs is same as requested */ 9104bb6cdceSJeffrey Huang if (num_vfs && num_vfs == bp->pf.active_vfs) 9114bb6cdceSJeffrey Huang goto sriov_cfg_exit; 9124bb6cdceSJeffrey Huang 9134bb6cdceSJeffrey Huang /* if there are previous existing VFs, clean them up */ 9144bb6cdceSJeffrey Huang bnxt_sriov_disable(bp); 9154bb6cdceSJeffrey Huang if (!num_vfs) 9164bb6cdceSJeffrey Huang goto sriov_cfg_exit; 917c0c050c5SMichael Chan 918c0c050c5SMichael Chan bnxt_sriov_enable(bp, &num_vfs); 919c0c050c5SMichael Chan 9204bb6cdceSJeffrey Huang sriov_cfg_exit: 921c0c050c5SMichael Chan bp->sriov_cfg = false; 922c0c050c5SMichael Chan wake_up(&bp->sriov_cfg_wait); 923c0c050c5SMichael Chan 924c0c050c5SMichael Chan return num_vfs; 925c0c050c5SMichael Chan } 926c0c050c5SMichael Chan 927c0c050c5SMichael Chan static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 928c0c050c5SMichael Chan void *encap_resp, __le64 encap_resp_addr, 929c0c050c5SMichael Chan __le16 encap_resp_cpr, u32 msg_size) 930c0c050c5SMichael Chan { 931bbf33d1dSEdwin Peer struct hwrm_fwd_resp_input *req; 932bbf33d1dSEdwin Peer int rc; 933c0c050c5SMichael Chan 93459895f59SMichael Chan if (BNXT_FWD_RESP_SIZE_ERR(msg_size)) 93559895f59SMichael Chan return -EINVAL; 93659895f59SMichael Chan 937bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FWD_RESP); 938bbf33d1dSEdwin Peer if (!rc) { 939c0c050c5SMichael Chan /* Set the new target id */ 940bbf33d1dSEdwin Peer req->target_id = cpu_to_le16(vf->fw_fid); 941bbf33d1dSEdwin Peer req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 942bbf33d1dSEdwin Peer req->encap_resp_len = cpu_to_le16(msg_size); 943bbf33d1dSEdwin Peer req->encap_resp_addr = encap_resp_addr; 944bbf33d1dSEdwin Peer req->encap_resp_cmpl_ring = encap_resp_cpr; 945bbf33d1dSEdwin Peer memcpy(req->encap_resp, encap_resp, msg_size); 946c0c050c5SMichael Chan 947bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 948bbf33d1dSEdwin Peer } 949a798302dSMichael Chan if (rc) 950c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_resp failed. rc:%d\n", rc); 951c0c050c5SMichael Chan return rc; 952c0c050c5SMichael Chan } 953c0c050c5SMichael Chan 954c0c050c5SMichael Chan static int bnxt_hwrm_fwd_err_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 955c0c050c5SMichael Chan u32 msg_size) 956c0c050c5SMichael Chan { 957bbf33d1dSEdwin Peer struct hwrm_reject_fwd_resp_input *req; 958bbf33d1dSEdwin Peer int rc; 959c0c050c5SMichael Chan 96059895f59SMichael Chan if (BNXT_REJ_FWD_RESP_SIZE_ERR(msg_size)) 96159895f59SMichael Chan return -EINVAL; 96259895f59SMichael Chan 963bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_REJECT_FWD_RESP); 964bbf33d1dSEdwin Peer if (!rc) { 965c0c050c5SMichael Chan /* Set the new target id */ 966bbf33d1dSEdwin Peer req->target_id = cpu_to_le16(vf->fw_fid); 967bbf33d1dSEdwin Peer req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 968bbf33d1dSEdwin Peer memcpy(req->encap_request, vf->hwrm_cmd_req_addr, msg_size); 969c0c050c5SMichael Chan 970bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 971bbf33d1dSEdwin Peer } 972a798302dSMichael Chan if (rc) 973c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_err_resp failed. rc:%d\n", rc); 974c0c050c5SMichael Chan return rc; 975c0c050c5SMichael Chan } 976c0c050c5SMichael Chan 977c0c050c5SMichael Chan static int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 978c0c050c5SMichael Chan u32 msg_size) 979c0c050c5SMichael Chan { 980bbf33d1dSEdwin Peer struct hwrm_exec_fwd_resp_input *req; 981bbf33d1dSEdwin Peer int rc; 982c0c050c5SMichael Chan 98359895f59SMichael Chan if (BNXT_EXEC_FWD_RESP_SIZE_ERR(msg_size)) 98459895f59SMichael Chan return -EINVAL; 98559895f59SMichael Chan 986bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_EXEC_FWD_RESP); 987bbf33d1dSEdwin Peer if (!rc) { 988c0c050c5SMichael Chan /* Set the new target id */ 989bbf33d1dSEdwin Peer req->target_id = cpu_to_le16(vf->fw_fid); 990bbf33d1dSEdwin Peer req->encap_resp_target_id = cpu_to_le16(vf->fw_fid); 991bbf33d1dSEdwin Peer memcpy(req->encap_request, vf->hwrm_cmd_req_addr, msg_size); 992c0c050c5SMichael Chan 993bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 994bbf33d1dSEdwin Peer } 995a798302dSMichael Chan if (rc) 996c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_exec_fw_resp failed. rc:%d\n", rc); 997c0c050c5SMichael Chan return rc; 998c0c050c5SMichael Chan } 999c0c050c5SMichael Chan 1000746df139SVasundhara Volam static int bnxt_vf_configure_mac(struct bnxt *bp, struct bnxt_vf_info *vf) 100191cdda40SVasundhara Volam { 100291cdda40SVasundhara Volam u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input); 100391cdda40SVasundhara Volam struct hwrm_func_vf_cfg_input *req = 100491cdda40SVasundhara Volam (struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr; 100591cdda40SVasundhara Volam 1006746df139SVasundhara Volam /* Allow VF to set a valid MAC address, if trust is set to on or 1007746df139SVasundhara Volam * if the PF assigned MAC address is zero 100891cdda40SVasundhara Volam */ 100991cdda40SVasundhara Volam if (req->enables & cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)) { 10102a516444SMichael Chan bool trust = bnxt_is_trusted_vf(bp, vf); 10112a516444SMichael Chan 101291cdda40SVasundhara Volam if (is_valid_ether_addr(req->dflt_mac_addr) && 10132a516444SMichael Chan (trust || !is_valid_ether_addr(vf->mac_addr) || 1014707e7e96SMichael Chan ether_addr_equal(req->dflt_mac_addr, vf->mac_addr))) { 101591cdda40SVasundhara Volam ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr); 101691cdda40SVasundhara Volam return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 101791cdda40SVasundhara Volam } 101891cdda40SVasundhara Volam return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 101991cdda40SVasundhara Volam } 102091cdda40SVasundhara Volam return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 102191cdda40SVasundhara Volam } 102291cdda40SVasundhara Volam 1023c0c050c5SMichael Chan static int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf) 1024c0c050c5SMichael Chan { 1025c0c050c5SMichael Chan u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input); 1026c0c050c5SMichael Chan struct hwrm_cfa_l2_filter_alloc_input *req = 1027c0c050c5SMichael Chan (struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr; 102891cdda40SVasundhara Volam bool mac_ok = false; 1029c0c050c5SMichael Chan 1030746df139SVasundhara Volam if (!is_valid_ether_addr((const u8 *)req->l2_addr)) 1031746df139SVasundhara Volam return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 1032746df139SVasundhara Volam 1033746df139SVasundhara Volam /* Allow VF to set a valid MAC address, if trust is set to on. 1034746df139SVasundhara Volam * Or VF MAC address must first match MAC address in PF's context. 103591cdda40SVasundhara Volam * Otherwise, it must match the VF MAC address if firmware spec >= 103691cdda40SVasundhara Volam * 1.2.2 103791cdda40SVasundhara Volam */ 10382a516444SMichael Chan if (bnxt_is_trusted_vf(bp, vf)) { 1039746df139SVasundhara Volam mac_ok = true; 1040746df139SVasundhara Volam } else if (is_valid_ether_addr(vf->mac_addr)) { 104191cdda40SVasundhara Volam if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr)) 104291cdda40SVasundhara Volam mac_ok = true; 104391cdda40SVasundhara Volam } else if (is_valid_ether_addr(vf->vf_mac_addr)) { 104491cdda40SVasundhara Volam if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr)) 104591cdda40SVasundhara Volam mac_ok = true; 104691cdda40SVasundhara Volam } else { 10476fd544c8SYueHaibing /* There are two cases: 10486fd544c8SYueHaibing * 1.If firmware spec < 0x10202,VF MAC address is not forwarded 10496fd544c8SYueHaibing * to the PF and so it doesn't have to match 10506fd544c8SYueHaibing * 2.Allow VF to modify it's own MAC when PF has not assigned a 10516fd544c8SYueHaibing * valid MAC address and firmware spec >= 0x10202 10526fd544c8SYueHaibing */ 105391cdda40SVasundhara Volam mac_ok = true; 105491cdda40SVasundhara Volam } 105591cdda40SVasundhara Volam if (mac_ok) 1056c0c050c5SMichael Chan return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 1057c0c050c5SMichael Chan return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 1058c0c050c5SMichael Chan } 1059c0c050c5SMichael Chan 1060c0c050c5SMichael Chan static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf) 1061c0c050c5SMichael Chan { 1062c0c050c5SMichael Chan int rc = 0; 1063c0c050c5SMichael Chan 1064c0c050c5SMichael Chan if (!(vf->flags & BNXT_VF_LINK_FORCED)) { 1065c0c050c5SMichael Chan /* real link */ 1066c0c050c5SMichael Chan rc = bnxt_hwrm_exec_fwd_resp( 1067c0c050c5SMichael Chan bp, vf, sizeof(struct hwrm_port_phy_qcfg_input)); 1068c0c050c5SMichael Chan } else { 10699d6b648cSMichael Chan struct hwrm_port_phy_qcfg_output phy_qcfg_resp = {0}; 1070c0c050c5SMichael Chan struct hwrm_port_phy_qcfg_input *phy_qcfg_req; 1071c0c050c5SMichael Chan 1072c0c050c5SMichael Chan phy_qcfg_req = 1073c0c050c5SMichael Chan (struct hwrm_port_phy_qcfg_input *)vf->hwrm_cmd_req_addr; 10743c10ed49SEdwin Peer mutex_lock(&bp->link_lock); 1075c0c050c5SMichael Chan memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp, 1076c0c050c5SMichael Chan sizeof(phy_qcfg_resp)); 10773c10ed49SEdwin Peer mutex_unlock(&bp->link_lock); 1078845adfe4SMichael Chan phy_qcfg_resp.resp_len = cpu_to_le16(sizeof(phy_qcfg_resp)); 1079c0c050c5SMichael Chan phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id; 1080845adfe4SMichael Chan phy_qcfg_resp.valid = 1; 1081c0c050c5SMichael Chan 1082c0c050c5SMichael Chan if (vf->flags & BNXT_VF_LINK_UP) { 1083c0c050c5SMichael Chan /* if physical link is down, force link up on VF */ 108473b9bad6SMichael Chan if (phy_qcfg_resp.link != 108573b9bad6SMichael Chan PORT_PHY_QCFG_RESP_LINK_LINK) { 1086c0c050c5SMichael Chan phy_qcfg_resp.link = 1087c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_LINK_LINK; 108811f15ed3SMichael Chan phy_qcfg_resp.link_speed = cpu_to_le16( 108911f15ed3SMichael Chan PORT_PHY_QCFG_RESP_LINK_SPEED_10GB); 1090acb20054SMichael Chan phy_qcfg_resp.duplex_cfg = 1091acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL; 1092acb20054SMichael Chan phy_qcfg_resp.duplex_state = 1093acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL; 1094c0c050c5SMichael Chan phy_qcfg_resp.pause = 1095c0c050c5SMichael Chan (PORT_PHY_QCFG_RESP_PAUSE_TX | 1096c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_PAUSE_RX); 1097c0c050c5SMichael Chan } 1098c0c050c5SMichael Chan } else { 1099c0c050c5SMichael Chan /* force link down */ 1100c0c050c5SMichael Chan phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK; 1101c0c050c5SMichael Chan phy_qcfg_resp.link_speed = 0; 1102acb20054SMichael Chan phy_qcfg_resp.duplex_state = 1103acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF; 1104c0c050c5SMichael Chan phy_qcfg_resp.pause = 0; 1105c0c050c5SMichael Chan } 1106c0c050c5SMichael Chan rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp, 1107c0c050c5SMichael Chan phy_qcfg_req->resp_addr, 1108c0c050c5SMichael Chan phy_qcfg_req->cmpl_ring, 1109c0c050c5SMichael Chan sizeof(phy_qcfg_resp)); 1110c0c050c5SMichael Chan } 1111c0c050c5SMichael Chan return rc; 1112c0c050c5SMichael Chan } 1113c0c050c5SMichael Chan 1114c0c050c5SMichael Chan static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf) 1115c0c050c5SMichael Chan { 1116c0c050c5SMichael Chan int rc = 0; 1117a8643e16SMichael Chan struct input *encap_req = vf->hwrm_cmd_req_addr; 1118a8643e16SMichael Chan u32 req_type = le16_to_cpu(encap_req->req_type); 1119c0c050c5SMichael Chan 1120c0c050c5SMichael Chan switch (req_type) { 112191cdda40SVasundhara Volam case HWRM_FUNC_VF_CFG: 1122746df139SVasundhara Volam rc = bnxt_vf_configure_mac(bp, vf); 112391cdda40SVasundhara Volam break; 1124c0c050c5SMichael Chan case HWRM_CFA_L2_FILTER_ALLOC: 1125c0c050c5SMichael Chan rc = bnxt_vf_validate_set_mac(bp, vf); 1126c0c050c5SMichael Chan break; 1127c0c050c5SMichael Chan case HWRM_FUNC_CFG: 1128c0c050c5SMichael Chan /* TODO Validate if VF is allowed to change mac address, 1129c0c050c5SMichael Chan * mtu, num of rings etc 1130c0c050c5SMichael Chan */ 1131c0c050c5SMichael Chan rc = bnxt_hwrm_exec_fwd_resp( 1132c0c050c5SMichael Chan bp, vf, sizeof(struct hwrm_func_cfg_input)); 1133c0c050c5SMichael Chan break; 1134c0c050c5SMichael Chan case HWRM_PORT_PHY_QCFG: 1135c0c050c5SMichael Chan rc = bnxt_vf_set_link(bp, vf); 1136c0c050c5SMichael Chan break; 1137c0c050c5SMichael Chan default: 1138c0c050c5SMichael Chan break; 1139c0c050c5SMichael Chan } 1140c0c050c5SMichael Chan return rc; 1141c0c050c5SMichael Chan } 1142c0c050c5SMichael Chan 1143c0c050c5SMichael Chan void bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 1144c0c050c5SMichael Chan { 1145c0c050c5SMichael Chan u32 i = 0, active_vfs = bp->pf.active_vfs, vf_id; 1146c0c050c5SMichael Chan 1147c0c050c5SMichael Chan /* Scan through VF's and process commands */ 1148c0c050c5SMichael Chan while (1) { 1149c0c050c5SMichael Chan vf_id = find_next_bit(bp->pf.vf_event_bmap, active_vfs, i); 1150c0c050c5SMichael Chan if (vf_id >= active_vfs) 1151c0c050c5SMichael Chan break; 1152c0c050c5SMichael Chan 1153c0c050c5SMichael Chan clear_bit(vf_id, bp->pf.vf_event_bmap); 1154c0c050c5SMichael Chan bnxt_vf_req_validate_snd(bp, &bp->pf.vf[vf_id]); 1155c0c050c5SMichael Chan i = vf_id + 1; 1156c0c050c5SMichael Chan } 1157c0c050c5SMichael Chan } 1158379a80a1SMichael Chan 115976660757SJakub Kicinski int bnxt_approve_mac(struct bnxt *bp, const u8 *mac, bool strict) 11607b3c8e27SMichael Chan { 1161bbf33d1dSEdwin Peer struct hwrm_func_vf_cfg_input *req; 11627b3c8e27SMichael Chan int rc = 0; 11637b3c8e27SMichael Chan 11647b3c8e27SMichael Chan if (!BNXT_VF(bp)) 11657b3c8e27SMichael Chan return 0; 11667b3c8e27SMichael Chan 11677b3c8e27SMichael Chan if (bp->hwrm_spec_code < 0x10202) { 11687b3c8e27SMichael Chan if (is_valid_ether_addr(bp->vf.mac_addr)) 11697b3c8e27SMichael Chan rc = -EADDRNOTAVAIL; 11707b3c8e27SMichael Chan goto mac_done; 11717b3c8e27SMichael Chan } 1172bbf33d1dSEdwin Peer 1173bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FUNC_VF_CFG); 1174bbf33d1dSEdwin Peer if (rc) 1175bbf33d1dSEdwin Peer goto mac_done; 1176bbf33d1dSEdwin Peer 1177bbf33d1dSEdwin Peer req->enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 1178bbf33d1dSEdwin Peer memcpy(req->dflt_mac_addr, mac, ETH_ALEN); 1179bbf33d1dSEdwin Peer if (!strict) 1180bbf33d1dSEdwin Peer hwrm_req_flags(bp, req, BNXT_HWRM_CTX_SILENT); 1181bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 11827b3c8e27SMichael Chan mac_done: 11837b3c8e27SMichael Chan if (rc && strict) { 11847b3c8e27SMichael Chan rc = -EADDRNOTAVAIL; 11857b3c8e27SMichael Chan netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", 11867b3c8e27SMichael Chan mac); 11877b3c8e27SMichael Chan return rc; 11887b3c8e27SMichael Chan } 11897b3c8e27SMichael Chan return 0; 11907b3c8e27SMichael Chan } 11917b3c8e27SMichael Chan 1192379a80a1SMichael Chan void bnxt_update_vf_mac(struct bnxt *bp) 1193379a80a1SMichael Chan { 1194bbf33d1dSEdwin Peer struct hwrm_func_qcaps_output *resp; 1195bbf33d1dSEdwin Peer struct hwrm_func_qcaps_input *req; 119692923cc7SMichael Chan bool inform_pf = false; 1197379a80a1SMichael Chan 1198bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_FUNC_QCAPS)) 1199bbf33d1dSEdwin Peer return; 1200379a80a1SMichael Chan 1201bbf33d1dSEdwin Peer req->fid = cpu_to_le16(0xffff); 1202bbf33d1dSEdwin Peer 1203bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 1204bbf33d1dSEdwin Peer if (hwrm_req_send(bp, req)) 1205379a80a1SMichael Chan goto update_vf_mac_exit; 1206379a80a1SMichael Chan 12073874d6a8SJeffrey Huang /* Store MAC address from the firmware. There are 2 cases: 12083874d6a8SJeffrey Huang * 1. MAC address is valid. It is assigned from the PF and we 12093874d6a8SJeffrey Huang * need to override the current VF MAC address with it. 12103874d6a8SJeffrey Huang * 2. MAC address is zero. The VF will use a random MAC address by 12113874d6a8SJeffrey Huang * default but the stored zero MAC will allow the VF user to change 12123874d6a8SJeffrey Huang * the random MAC address using ndo_set_mac_address() if he wants. 12133874d6a8SJeffrey Huang */ 121492923cc7SMichael Chan if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr)) { 121511f15ed3SMichael Chan memcpy(bp->vf.mac_addr, resp->mac_address, ETH_ALEN); 121692923cc7SMichael Chan /* This means we are now using our own MAC address, let 121792923cc7SMichael Chan * the PF know about this MAC address. 121892923cc7SMichael Chan */ 121992923cc7SMichael Chan if (!is_valid_ether_addr(bp->vf.mac_addr)) 122092923cc7SMichael Chan inform_pf = true; 122192923cc7SMichael Chan } 12223874d6a8SJeffrey Huang 12233874d6a8SJeffrey Huang /* overwrite netdev dev_addr with admin VF MAC */ 12243874d6a8SJeffrey Huang if (is_valid_ether_addr(bp->vf.mac_addr)) 1225a96d317fSJakub Kicinski eth_hw_addr_set(bp->dev, bp->vf.mac_addr); 1226379a80a1SMichael Chan update_vf_mac_exit: 1227bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 122892923cc7SMichael Chan if (inform_pf) 122992923cc7SMichael Chan bnxt_approve_mac(bp, bp->dev->dev_addr, false); 1230379a80a1SMichael Chan } 1231379a80a1SMichael Chan 1232c0c050c5SMichael Chan #else 1233c0c050c5SMichael Chan 12342cd86968SVasundhara Volam int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) 1235702d5011SMichael Chan { 1236702d5011SMichael Chan if (*num_vfs) 1237702d5011SMichael Chan return -EOPNOTSUPP; 1238702d5011SMichael Chan return 0; 1239702d5011SMichael Chan } 1240702d5011SMichael Chan 1241c0c050c5SMichael Chan void bnxt_sriov_disable(struct bnxt *bp) 1242c0c050c5SMichael Chan { 1243c0c050c5SMichael Chan } 1244c0c050c5SMichael Chan 1245c0c050c5SMichael Chan void bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 1246c0c050c5SMichael Chan { 1247379a80a1SMichael Chan netdev_err(bp->dev, "Invalid VF message received when SRIOV is not enable\n"); 1248379a80a1SMichael Chan } 1249379a80a1SMichael Chan 1250379a80a1SMichael Chan void bnxt_update_vf_mac(struct bnxt *bp) 1251379a80a1SMichael Chan { 1252c0c050c5SMichael Chan } 125384c33dd3SMichael Chan 125476660757SJakub Kicinski int bnxt_approve_mac(struct bnxt *bp, const u8 *mac, bool strict) 125584c33dd3SMichael Chan { 125684c33dd3SMichael Chan return 0; 125784c33dd3SMichael Chan } 1258c0c050c5SMichael Chan #endif 1259